code.gitea.io/gitea@v1.19.3/modules/indexer/code/wrapped.go (about)

     1  // Copyright 2019 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package code
     5  
     6  import (
     7  	"context"
     8  	"fmt"
     9  	"sync"
    10  
    11  	repo_model "code.gitea.io/gitea/models/repo"
    12  	"code.gitea.io/gitea/modules/log"
    13  )
    14  
    15  var indexer = newWrappedIndexer()
    16  
    17  // ErrWrappedIndexerClosed is the error returned if the indexer was closed before it was ready
    18  var ErrWrappedIndexerClosed = fmt.Errorf("Indexer closed before ready")
    19  
    20  type wrappedIndexer struct {
    21  	internal Indexer
    22  	lock     sync.RWMutex
    23  	cond     *sync.Cond
    24  	closed   bool
    25  }
    26  
    27  func newWrappedIndexer() *wrappedIndexer {
    28  	w := &wrappedIndexer{}
    29  	w.cond = sync.NewCond(w.lock.RLocker())
    30  	return w
    31  }
    32  
    33  func (w *wrappedIndexer) set(indexer Indexer) {
    34  	w.lock.Lock()
    35  	defer w.lock.Unlock()
    36  	if w.closed {
    37  		// Too late!
    38  		indexer.Close()
    39  	}
    40  	w.internal = indexer
    41  	w.cond.Broadcast()
    42  }
    43  
    44  func (w *wrappedIndexer) get() (Indexer, error) {
    45  	w.lock.RLock()
    46  	defer w.lock.RUnlock()
    47  	if w.internal == nil {
    48  		if w.closed {
    49  			return nil, ErrWrappedIndexerClosed
    50  		}
    51  		w.cond.Wait()
    52  		if w.closed {
    53  			return nil, ErrWrappedIndexerClosed
    54  		}
    55  	}
    56  	return w.internal, nil
    57  }
    58  
    59  // SetAvailabilityChangeCallback sets callback that will be triggered when availability changes
    60  func (w *wrappedIndexer) SetAvailabilityChangeCallback(callback func(bool)) {
    61  	indexer, err := w.get()
    62  	if err != nil {
    63  		log.Error("Failed to get indexer: %v", err)
    64  		return
    65  	}
    66  	indexer.SetAvailabilityChangeCallback(callback)
    67  }
    68  
    69  // Ping checks if elastic is available
    70  func (w *wrappedIndexer) Ping() bool {
    71  	indexer, err := w.get()
    72  	if err != nil {
    73  		log.Warn("Failed to get indexer: %v", err)
    74  		return false
    75  	}
    76  	return indexer.Ping()
    77  }
    78  
    79  func (w *wrappedIndexer) Index(ctx context.Context, repo *repo_model.Repository, sha string, changes *repoChanges) error {
    80  	indexer, err := w.get()
    81  	if err != nil {
    82  		return err
    83  	}
    84  	return indexer.Index(ctx, repo, sha, changes)
    85  }
    86  
    87  func (w *wrappedIndexer) Delete(repoID int64) error {
    88  	indexer, err := w.get()
    89  	if err != nil {
    90  		return err
    91  	}
    92  	return indexer.Delete(repoID)
    93  }
    94  
    95  func (w *wrappedIndexer) Search(ctx context.Context, repoIDs []int64, language, keyword string, page, pageSize int, isMatch bool) (int64, []*SearchResult, []*SearchResultLanguages, error) {
    96  	indexer, err := w.get()
    97  	if err != nil {
    98  		return 0, nil, nil, err
    99  	}
   100  	return indexer.Search(ctx, repoIDs, language, keyword, page, pageSize, isMatch)
   101  }
   102  
   103  func (w *wrappedIndexer) Close() {
   104  	w.lock.Lock()
   105  	defer w.lock.Unlock()
   106  	if w.closed {
   107  		return
   108  	}
   109  	w.closed = true
   110  	w.cond.Broadcast()
   111  	if w.internal != nil {
   112  		w.internal.Close()
   113  	}
   114  }