From 0c27fd131cee17921b875a98906ed9c951fe9475 Mon Sep 17 00:00:00 2001
From: Xiaoxuan Wang <wangxiaoxuan119@gmail.com>
Date: Thu, 26 Oct 2023 09:18:14 +0000
Subject: [PATCH] resolved comments

Signed-off-by: Xiaoxuan Wang <wangxiaoxuan119@gmail.com>
---
 content/oci/oci.go      | 31 +++++++++++++++++++++----------
 content/oci/oci_test.go |  2 +-
 2 files changed, 22 insertions(+), 11 deletions(-)

diff --git a/content/oci/oci.go b/content/oci/oci.go
index 372e1d3e8..a325c89d1 100644
--- a/content/oci/oci.go
+++ b/content/oci/oci.go
@@ -53,12 +53,16 @@ type Store struct {
 	root          string
 	indexPath     string
 	index         *ocispec.Index
-	indexLock     sync.Mutex
-	sync          sync.RWMutex
-
-	storage     *Storage
-	tagResolver *resolver.Memory
-	graph       *graph.Memory
+	storage       *Storage
+	tagResolver   *resolver.Memory
+	graph         *graph.Memory
+
+	// sync ensures that most operations can be done concurrently, while Delete
+	// has the exclusive access to Store if a delete operation is underway. Operations
+	// such as Fetch, Push use sync.RLock(), while Delete uses sync.Lock().
+	sync sync.RWMutex
+	// indexLock ensures that only one process is writing to the index.
+	indexLock sync.Mutex
 }
 
 // New creates a new OCI store with context.Background().
@@ -100,8 +104,8 @@ func NewWithContext(ctx context.Context, root string) (*Store, error) {
 }
 
 // Fetch fetches the content identified by the descriptor. It returns an io.ReadCloser.
-// It's recommended to close the io.ReadCloser before a DeletableStore.Delete
-// operation, otherwise Delete may fail (for example on NTFS file systems).
+// It's recommended to close the io.ReadCloser before a Delete operation, otherwise
+// Delete may fail (for example on NTFS file systems).
 func (s *Store) Fetch(ctx context.Context, target ocispec.Descriptor) (io.ReadCloser, error) {
 	s.sync.RLock()
 	defer s.sync.RUnlock()
@@ -154,7 +158,7 @@ func (s *Store) Delete(ctx context.Context, target ocispec.Descriptor) error {
 		return err
 	}
 	if untagged && s.AutoSaveIndex {
-		err := s.SaveIndex()
+		err := s.saveIndex()
 		if err != nil {
 			return err
 		}
@@ -197,7 +201,7 @@ func (s *Store) tag(ctx context.Context, desc ocispec.Descriptor, reference stri
 		return err
 	}
 	if s.AutoSaveIndex {
-		return s.SaveIndex()
+		return s.saveIndex()
 	}
 	return nil
 }
@@ -318,6 +322,13 @@ func (s *Store) loadIndexFile(ctx context.Context) error {
 //   - If AutoSaveIndex is set to false, it's the caller's responsibility
 //     to manually call this method when needed.
 func (s *Store) SaveIndex() error {
+	s.sync.RLock()
+	defer s.sync.RUnlock()
+
+	return s.saveIndex()
+}
+
+func (s *Store) saveIndex() error {
 	s.indexLock.Lock()
 	defer s.indexLock.Unlock()
 
diff --git a/content/oci/oci_test.go b/content/oci/oci_test.go
index d7dec3300..914b83b2c 100644
--- a/content/oci/oci_test.go
+++ b/content/oci/oci_test.go
@@ -644,7 +644,7 @@ func TestStore_DisableAutoSaveIndex(t *testing.T) {
 	if got, want := len(s.index.Manifests), 0; got != want {
 		t.Errorf("len(index.Manifests) = %v, want %v", got, want)
 	}
-	if err := s.SaveIndex(); err != nil {
+	if err := s.saveIndex(); err != nil {
 		t.Fatal("Store.SaveIndex() error =", err)
 	}
 	// test index file again