| 
									
										
										
										
											2021-04-20 01:30:42 +08:00
										 |  |  | // Copyright (c) 2015-2021 MinIO, Inc.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This file is part of MinIO Object Storage stack
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This program is free software: you can redistribute it and/or modify
 | 
					
						
							|  |  |  | // it under the terms of the GNU Affero General Public License as published by
 | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or
 | 
					
						
							|  |  |  | // (at your option) any later version.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This program is distributed in the hope that it will be useful
 | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
					
						
							|  |  |  | // GNU Affero General Public License for more details.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // You should have received a copy of the GNU Affero General Public License
 | 
					
						
							|  |  |  | // along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package cmd | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"context" | 
					
						
							|  |  |  | 	"encoding/binary" | 
					
						
							|  |  |  | 	"errors" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"io" | 
					
						
							|  |  |  | 	"os" | 
					
						
							|  |  |  | 	"path/filepath" | 
					
						
							|  |  |  | 	"sync" | 
					
						
							|  |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-06-02 05:59:40 +08:00
										 |  |  | 	"github.com/minio/minio/internal/logger" | 
					
						
							| 
									
										
										
										
											2021-04-20 01:30:42 +08:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //go:generate msgp -file $GOFILE -unexported
 | 
					
						
							| 
									
										
										
										
											2023-08-04 05:16:15 +08:00
										 |  |  | //msgp:ignore TierJournal tierDiskJournal walkfn
 | 
					
						
							| 
									
										
										
										
											2021-04-20 01:30:42 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-01 10:32:07 +08:00
										 |  |  | type tierDiskJournal struct { | 
					
						
							| 
									
										
										
										
											2021-04-20 01:30:42 +08:00
										 |  |  | 	sync.RWMutex | 
					
						
							|  |  |  | 	diskPath string | 
					
						
							|  |  |  | 	file     *os.File // active journal file
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-04 05:16:15 +08:00
										 |  |  | // TierJournal holds an in-memory and an on-disk delete journal of tiered content.
 | 
					
						
							|  |  |  | type TierJournal struct { | 
					
						
							| 
									
										
										
										
											2021-07-01 10:32:07 +08:00
										 |  |  | 	*tierDiskJournal // for processing legacy journal entries
 | 
					
						
							|  |  |  | 	*tierMemJournal  // for processing new journal entries
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-20 01:30:42 +08:00
										 |  |  | type jentry struct { | 
					
						
							| 
									
										
										
										
											2021-06-04 05:26:51 +08:00
										 |  |  | 	ObjName   string `msg:"obj"` | 
					
						
							|  |  |  | 	VersionID string `msg:"vid"` | 
					
						
							|  |  |  | 	TierName  string `msg:"tier"` | 
					
						
							| 
									
										
										
										
											2021-04-20 01:30:42 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const ( | 
					
						
							|  |  |  | 	tierJournalVersion = 1 | 
					
						
							|  |  |  | 	tierJournalHdrLen  = 2 // 2 bytes
 | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-03 01:15:06 +08:00
										 |  |  | var errUnsupportedJournalVersion = errors.New("unsupported pending deletes journal version") | 
					
						
							| 
									
										
										
										
											2021-06-04 05:26:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-01 10:32:07 +08:00
										 |  |  | func newTierDiskJournal() *tierDiskJournal { | 
					
						
							|  |  |  | 	return &tierDiskJournal{} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-04 05:16:15 +08:00
										 |  |  | // NewTierJournal initializes tier deletion journal
 | 
					
						
							|  |  |  | func NewTierJournal() *TierJournal { | 
					
						
							|  |  |  | 	j := &TierJournal{ | 
					
						
							|  |  |  | 		tierMemJournal:  newTierMemJournal(1000), | 
					
						
							| 
									
										
										
										
											2021-07-01 10:32:07 +08:00
										 |  |  | 		tierDiskJournal: newTierDiskJournal(), | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-08-04 05:16:15 +08:00
										 |  |  | 	return j | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2022-07-09 03:17:02 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-04 05:16:15 +08:00
										 |  |  | // Init intializes an in-memory journal built using a
 | 
					
						
							|  |  |  | // buffered channel for new journal entries. It also initializes the on-disk
 | 
					
						
							|  |  |  | // journal only to process existing journal entries made from previous versions.
 | 
					
						
							|  |  |  | func (t *TierJournal) Init(ctx context.Context) error { | 
					
						
							| 
									
										
										
										
											2021-06-06 00:10:32 +08:00
										 |  |  | 	for _, diskPath := range globalEndpoints.LocalDisksPaths() { | 
					
						
							| 
									
										
										
										
											2023-08-04 05:16:15 +08:00
										 |  |  | 		t.diskPath = diskPath | 
					
						
							| 
									
										
										
										
											2021-06-06 00:10:32 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-04 05:16:15 +08:00
										 |  |  | 		go t.deletePending(ctx)  // for existing journal entries from previous MinIO versions
 | 
					
						
							|  |  |  | 		go t.processEntries(ctx) // for newer journal entries circa free-versions
 | 
					
						
							|  |  |  | 		return nil | 
					
						
							| 
									
										
										
										
											2021-04-20 01:30:42 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-04 05:16:15 +08:00
										 |  |  | 	return errors.New("no local drive found") | 
					
						
							| 
									
										
										
										
											2021-04-20 01:30:42 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // rotate rotates the journal. If a read-only journal already exists it does
 | 
					
						
							|  |  |  | // nothing. Otherwise renames the active journal to a read-only journal and
 | 
					
						
							|  |  |  | // opens a new active journal.
 | 
					
						
							| 
									
										
										
										
											2021-07-01 10:32:07 +08:00
										 |  |  | func (jd *tierDiskJournal) rotate() error { | 
					
						
							| 
									
										
										
										
											2021-04-20 01:30:42 +08:00
										 |  |  | 	// Do nothing if a read-only journal file already exists.
 | 
					
						
							| 
									
										
										
										
											2021-07-01 10:32:07 +08:00
										 |  |  | 	if _, err := os.Stat(jd.ReadOnlyPath()); err == nil { | 
					
						
							| 
									
										
										
										
											2021-04-20 01:30:42 +08:00
										 |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-07-09 03:17:02 +08:00
										 |  |  | 	// Close the active journal if present and delete it.
 | 
					
						
							|  |  |  | 	return jd.Close() | 
					
						
							| 
									
										
										
										
											2021-04-20 01:30:42 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-01 10:32:07 +08:00
										 |  |  | type walkFn func(ctx context.Context, objName, rvID, tierName string) error | 
					
						
							| 
									
										
										
										
											2021-04-20 01:30:42 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-01 10:32:07 +08:00
										 |  |  | func (jd *tierDiskJournal) ReadOnlyPath() string { | 
					
						
							|  |  |  | 	return filepath.Join(jd.diskPath, minioMetaBucket, "ilm", "deletion-journal.ro.bin") | 
					
						
							| 
									
										
										
										
											2021-04-20 01:30:42 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-01 10:32:07 +08:00
										 |  |  | func (jd *tierDiskJournal) JournalPath() string { | 
					
						
							|  |  |  | 	return filepath.Join(jd.diskPath, minioMetaBucket, "ilm", "deletion-journal.bin") | 
					
						
							| 
									
										
										
										
											2021-04-20 01:30:42 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-01 10:32:07 +08:00
										 |  |  | func (jd *tierDiskJournal) WalkEntries(ctx context.Context, fn walkFn) { | 
					
						
							| 
									
										
										
										
											2022-07-09 03:17:02 +08:00
										 |  |  | 	if err := jd.rotate(); err != nil { | 
					
						
							| 
									
										
										
										
											2021-07-01 10:32:07 +08:00
										 |  |  | 		logger.LogIf(ctx, fmt.Errorf("tier-journal: failed to rotate pending deletes journal %s", err)) | 
					
						
							| 
									
										
										
										
											2021-04-20 01:30:42 +08:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-01 10:32:07 +08:00
										 |  |  | 	ro, err := jd.OpenRO() | 
					
						
							| 
									
										
										
										
											2021-04-20 01:30:42 +08:00
										 |  |  | 	switch { | 
					
						
							|  |  |  | 	case errors.Is(err, os.ErrNotExist): | 
					
						
							|  |  |  | 		return // No read-only journal to process; nothing to do.
 | 
					
						
							|  |  |  | 	case err != nil: | 
					
						
							| 
									
										
										
										
											2021-07-01 10:32:07 +08:00
										 |  |  | 		logger.LogIf(ctx, fmt.Errorf("tier-journal: failed open read-only journal for processing %s", err)) | 
					
						
							| 
									
										
										
										
											2021-04-20 01:30:42 +08:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	defer ro.Close() | 
					
						
							| 
									
										
										
										
											2023-07-07 07:02:08 +08:00
										 |  |  | 	mr := msgpNewReader(ro) | 
					
						
							|  |  |  | 	defer readMsgpReaderPoolPut(mr) | 
					
						
							| 
									
										
										
										
											2021-06-04 05:26:51 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-20 01:30:42 +08:00
										 |  |  | 	done := false | 
					
						
							|  |  |  | 	for { | 
					
						
							|  |  |  | 		var entry jentry | 
					
						
							|  |  |  | 		err := entry.DecodeMsg(mr) | 
					
						
							|  |  |  | 		if errors.Is(err, io.EOF) { | 
					
						
							|  |  |  | 			done = true | 
					
						
							|  |  |  | 			break | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2021-07-01 10:32:07 +08:00
										 |  |  | 			logger.LogIf(ctx, fmt.Errorf("tier-journal: failed to decode journal entry %s", err)) | 
					
						
							| 
									
										
										
										
											2021-04-20 01:30:42 +08:00
										 |  |  | 			break | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-07-01 10:32:07 +08:00
										 |  |  | 		err = fn(ctx, entry.ObjName, entry.VersionID, entry.TierName) | 
					
						
							| 
									
										
										
										
											2021-04-20 01:30:42 +08:00
										 |  |  | 		if err != nil && !isErrObjectNotFound(err) { | 
					
						
							| 
									
										
										
										
											2021-07-01 10:32:07 +08:00
										 |  |  | 			logger.LogIf(ctx, fmt.Errorf("tier-journal: failed to delete transitioned object %s from %s due to %s", entry.ObjName, entry.TierName, err)) | 
					
						
							| 
									
										
										
										
											2021-06-04 05:26:51 +08:00
										 |  |  | 			// We add the entry into the active journal to try again
 | 
					
						
							|  |  |  | 			// later.
 | 
					
						
							| 
									
										
										
										
											2021-07-01 10:32:07 +08:00
										 |  |  | 			jd.addEntry(entry) | 
					
						
							| 
									
										
										
										
											2021-04-20 01:30:42 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if done { | 
					
						
							| 
									
										
										
										
											2021-07-01 10:32:07 +08:00
										 |  |  | 		os.Remove(jd.ReadOnlyPath()) | 
					
						
							| 
									
										
										
										
											2021-04-20 01:30:42 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-01 10:32:07 +08:00
										 |  |  | func deleteObjectFromRemoteTier(ctx context.Context, objName, rvID, tierName string) error { | 
					
						
							| 
									
										
										
										
											2021-04-20 01:30:42 +08:00
										 |  |  | 	w, err := globalTierConfigMgr.getDriver(tierName) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-07-01 10:32:07 +08:00
										 |  |  | 	err = w.Remove(ctx, objName, remoteVersionID(rvID)) | 
					
						
							| 
									
										
										
										
											2021-04-20 01:30:42 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-01 10:32:07 +08:00
										 |  |  | func (jd *tierDiskJournal) deletePending(ctx context.Context) { | 
					
						
							| 
									
										
										
										
											2021-04-20 01:30:42 +08:00
										 |  |  | 	ticker := time.NewTicker(30 * time.Minute) | 
					
						
							|  |  |  | 	defer ticker.Stop() | 
					
						
							|  |  |  | 	for { | 
					
						
							|  |  |  | 		select { | 
					
						
							|  |  |  | 		case <-ticker.C: | 
					
						
							| 
									
										
										
										
											2021-07-01 10:32:07 +08:00
										 |  |  | 			jd.WalkEntries(ctx, deleteObjectFromRemoteTier) | 
					
						
							| 
									
										
										
										
											2021-04-20 01:30:42 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-01 10:32:07 +08:00
										 |  |  | 		case <-ctx.Done(): | 
					
						
							|  |  |  | 			jd.Close() | 
					
						
							| 
									
										
										
										
											2021-04-20 01:30:42 +08:00
										 |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-01 10:32:07 +08:00
										 |  |  | func (jd *tierDiskJournal) addEntry(je jentry) error { | 
					
						
							| 
									
										
										
										
											2021-04-20 01:30:42 +08:00
										 |  |  | 	// Open journal if it hasn't been
 | 
					
						
							| 
									
										
										
										
											2021-07-01 10:32:07 +08:00
										 |  |  | 	err := jd.Open() | 
					
						
							| 
									
										
										
										
											2021-04-20 01:30:42 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	b, err := je.MarshalMsg(nil) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-01 10:32:07 +08:00
										 |  |  | 	jd.Lock() | 
					
						
							|  |  |  | 	defer jd.Unlock() | 
					
						
							|  |  |  | 	_, err = jd.file.Write(b) | 
					
						
							| 
									
										
										
										
											2021-04-20 01:30:42 +08:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2021-07-01 10:32:07 +08:00
										 |  |  | 		jd.file = nil // reset to allow subsequent reopen when file/disk is available.
 | 
					
						
							| 
									
										
										
										
											2021-04-20 01:30:42 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return err | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Close closes the active journal and renames it to read-only for pending
 | 
					
						
							|  |  |  | // deletes processing. Note: calling Close on a closed journal is a no-op.
 | 
					
						
							| 
									
										
										
										
											2021-07-01 10:32:07 +08:00
										 |  |  | func (jd *tierDiskJournal) Close() error { | 
					
						
							|  |  |  | 	jd.Lock() | 
					
						
							|  |  |  | 	defer jd.Unlock() | 
					
						
							|  |  |  | 	if jd.file == nil { // already closed
 | 
					
						
							| 
									
										
										
										
											2021-04-20 01:30:42 +08:00
										 |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var ( | 
					
						
							|  |  |  | 		f   *os.File | 
					
						
							|  |  |  | 		fi  os.FileInfo | 
					
						
							|  |  |  | 		err error | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	// Setting j.file to nil
 | 
					
						
							| 
									
										
										
										
											2021-07-01 10:32:07 +08:00
										 |  |  | 	f, jd.file = jd.file, f | 
					
						
							| 
									
										
										
										
											2021-04-20 01:30:42 +08:00
										 |  |  | 	if fi, err = f.Stat(); err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-07-09 03:17:02 +08:00
										 |  |  | 	f.Close() // close before rename()
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-20 01:30:42 +08:00
										 |  |  | 	// Skip renaming active journal if empty.
 | 
					
						
							|  |  |  | 	if fi.Size() == tierJournalHdrLen { | 
					
						
							| 
									
										
										
										
											2022-07-09 03:17:02 +08:00
										 |  |  | 		return os.Remove(jd.JournalPath()) | 
					
						
							| 
									
										
										
										
											2021-04-20 01:30:42 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-01 10:32:07 +08:00
										 |  |  | 	jPath := jd.JournalPath() | 
					
						
							|  |  |  | 	jroPath := jd.ReadOnlyPath() | 
					
						
							| 
									
										
										
										
											2021-04-20 01:30:42 +08:00
										 |  |  | 	// Rotate active journal to perform pending deletes.
 | 
					
						
							| 
									
										
										
										
											2022-07-09 03:17:02 +08:00
										 |  |  | 	return os.Rename(jPath, jroPath) | 
					
						
							| 
									
										
										
										
											2021-04-20 01:30:42 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Open opens a new active journal. Note: calling Open on an opened journal is a
 | 
					
						
							|  |  |  | // no-op.
 | 
					
						
							| 
									
										
										
										
											2021-07-01 10:32:07 +08:00
										 |  |  | func (jd *tierDiskJournal) Open() error { | 
					
						
							|  |  |  | 	jd.Lock() | 
					
						
							|  |  |  | 	defer jd.Unlock() | 
					
						
							|  |  |  | 	if jd.file != nil { // already open
 | 
					
						
							| 
									
										
										
										
											2021-04-20 01:30:42 +08:00
										 |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var err error | 
					
						
							| 
									
										
										
										
											2022-08-02 04:22:43 +08:00
										 |  |  | 	jd.file, err = OpenFile(jd.JournalPath(), os.O_APPEND|os.O_CREATE|os.O_WRONLY|writeMode, 0o666) | 
					
						
							| 
									
										
										
										
											2021-04-20 01:30:42 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// write journal version header if active journal is empty
 | 
					
						
							| 
									
										
										
										
											2021-07-01 10:32:07 +08:00
										 |  |  | 	fi, err := jd.file.Stat() | 
					
						
							| 
									
										
										
										
											2021-04-20 01:30:42 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if fi.Size() == 0 { | 
					
						
							|  |  |  | 		var data [tierJournalHdrLen]byte | 
					
						
							|  |  |  | 		binary.LittleEndian.PutUint16(data[:], tierJournalVersion) | 
					
						
							| 
									
										
										
										
											2021-07-01 10:32:07 +08:00
										 |  |  | 		_, err = jd.file.Write(data[:]) | 
					
						
							| 
									
										
										
										
											2021-04-20 01:30:42 +08:00
										 |  |  | 		if err != nil { | 
					
						
							|  |  |  | 			return err | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-07-01 10:32:07 +08:00
										 |  |  | func (jd *tierDiskJournal) OpenRO() (io.ReadCloser, error) { | 
					
						
							| 
									
										
										
										
											2022-08-02 04:22:43 +08:00
										 |  |  | 	file, err := Open(jd.ReadOnlyPath()) | 
					
						
							| 
									
										
										
										
											2021-04-20 01:30:42 +08:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// read journal version header
 | 
					
						
							|  |  |  | 	var data [tierJournalHdrLen]byte | 
					
						
							|  |  |  | 	if _, err := io.ReadFull(file, data[:]); err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch binary.LittleEndian.Uint16(data[:]) { | 
					
						
							|  |  |  | 	case tierJournalVersion: | 
					
						
							| 
									
										
										
										
											2021-06-04 05:26:51 +08:00
										 |  |  | 		return file, nil | 
					
						
							| 
									
										
										
										
											2021-04-20 01:30:42 +08:00
										 |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2021-06-04 05:26:51 +08:00
										 |  |  | 		return nil, errUnsupportedJournalVersion | 
					
						
							| 
									
										
										
										
											2021-04-20 01:30:42 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-06-04 05:26:51 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // jentryV1 represents the entry in the journal before RemoteVersionID was
 | 
					
						
							|  |  |  | // added. It remains here for use in tests for the struct element addition.
 | 
					
						
							|  |  |  | type jentryV1 struct { | 
					
						
							|  |  |  | 	ObjName  string `msg:"obj"` | 
					
						
							|  |  |  | 	TierName string `msg:"tier"` | 
					
						
							| 
									
										
										
										
											2021-04-20 01:30:42 +08:00
										 |  |  | } |