Skip to content

Commit

Permalink
reimplemented caching code, added call deduplication
Browse files Browse the repository at this point in the history
  • Loading branch information
pk910 committed Aug 1, 2023
1 parent 537fce8 commit f44a1d0
Show file tree
Hide file tree
Showing 11 changed files with 238 additions and 154 deletions.
10 changes: 9 additions & 1 deletion cmd/explorer/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,17 @@ func main() {
}

if cfg.Frontend.Enabled {
err = services.StartFrontendCache()
if err != nil {
logger.Fatalf("error starting frontend cache service: %v", err)
}

startFrontend()
}
} else {
utils.WaitForCtrlC()

logger.Println("exiting...")
}
}

func startFrontend() {
Expand Down
33 changes: 17 additions & 16 deletions handlers/epoch.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,25 +56,30 @@ func Epoch(w http.ResponseWriter, r *http.Request) {
func getEpochPageData(epoch uint64) *models.EpochPageData {
pageData := &models.EpochPageData{}
pageCacheKey := fmt.Sprintf("epoch:%v", epoch)
if !utils.Config.Frontend.Debug && services.GlobalBeaconService.GetFrontendCache(pageCacheKey, pageData) == nil {
logrus.Printf("epoch page served from cache: %v", epoch)
pageData = services.GlobalFrontendCache.ProcessCachedPage(pageCacheKey, true, pageData, func(pageCall *services.FrontendCacheProcessingPage) interface{} {
pageData, cacheTimeout := buildEpochPageData(epoch)
pageCall.CacheTimeout = cacheTimeout
return pageData
}
}).(*models.EpochPageData)
return pageData
}

func buildEpochPageData(epoch uint64) (*models.EpochPageData, time.Duration) {
logrus.Printf("epoch page called: %v", epoch)

now := time.Now()
currentSlot := utils.TimeToSlot(uint64(now.Unix()))
currentEpoch := utils.EpochOfSlot(currentSlot)
if epoch > currentEpoch {
return nil
return nil, -1
}

finalizedHead, _ := services.GlobalBeaconService.GetFinalizedBlockHead()
slotAssignments, syncedEpochs := services.GlobalBeaconService.GetProposerAssignments(epoch, epoch)

dbEpochs := services.GlobalBeaconService.GetDbEpochs(epoch, 1)
if dbEpochs[0] == nil {
return nil
return nil, -1
}
dbEpoch := dbEpochs[0]
nextEpoch := epoch + 1
Expand All @@ -83,7 +88,7 @@ func getEpochPageData(epoch uint64) *models.EpochPageData {
}
firstSlot := epoch * utils.Config.Chain.Config.SlotsPerEpoch
lastSlot := firstSlot + utils.Config.Chain.Config.SlotsPerEpoch - 1
pageData = &models.EpochPageData{
pageData := &models.EpochPageData{
Epoch: epoch,
PreviousEpoch: epoch - 1,
NextEpoch: nextEpoch,
Expand Down Expand Up @@ -175,15 +180,11 @@ func getEpochPageData(epoch uint64) *models.EpochPageData {
}
pageData.BlockCount = uint64(blockCount)

if pageCacheKey != "" {
var cacheTimeout time.Duration
if pageData.Finalized {
cacheTimeout = 30 * time.Minute
} else {
cacheTimeout = 12 * time.Second
}
services.GlobalBeaconService.SetFrontendCache(pageCacheKey, pageData, cacheTimeout)
var cacheTimeout time.Duration
if pageData.Finalized {
cacheTimeout = 30 * time.Minute
} else {
cacheTimeout = 12 * time.Second
}

return pageData
return pageData, cacheTimeout
}
28 changes: 15 additions & 13 deletions handlers/epochs.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,17 @@ func Epochs(w http.ResponseWriter, r *http.Request) {
func getEpochsPageData(firstEpoch uint64, pageSize uint64) *models.EpochsPageData {
pageData := &models.EpochsPageData{}
pageCacheKey := fmt.Sprintf("epochs:%v:%v", firstEpoch, pageSize)
if !utils.Config.Frontend.Debug && services.GlobalBeaconService.GetFrontendCache(pageCacheKey, pageData) == nil {
logrus.Printf("epochs page served from cache: %v:%v", firstEpoch, pageSize)
pageData = services.GlobalFrontendCache.ProcessCachedPage(pageCacheKey, true, pageData, func(pageCall *services.FrontendCacheProcessingPage) interface{} {
pageData, cacheTimeout := buildEpochsPageData(firstEpoch, pageSize)
pageCall.CacheTimeout = cacheTimeout
return pageData
}
}).(*models.EpochsPageData)
return pageData
}

func buildEpochsPageData(firstEpoch uint64, pageSize uint64) (*models.EpochsPageData, time.Duration) {
logrus.Printf("epochs page called: %v:%v", firstEpoch, pageSize)
pageData := &models.EpochsPageData{}

now := time.Now()
currentEpoch := utils.TimeToEpoch(now)
Expand Down Expand Up @@ -133,15 +139,11 @@ func getEpochsPageData(firstEpoch uint64, pageSize uint64) *models.EpochsPageDat
pageData.FirstEpoch = firstEpoch
pageData.LastEpoch = firstEpoch - pageData.EpochCount + 1

if pageCacheKey != "" {
var cacheTimeout time.Duration
if firstEpoch+2 < uint64(currentEpoch) {
cacheTimeout = 10 * time.Minute
} else {
cacheTimeout = 12 * time.Second
}
services.GlobalBeaconService.SetFrontendCache(pageCacheKey, pageData, cacheTimeout)
var cacheTimeout time.Duration
if firstEpoch+2 < uint64(currentEpoch) {
cacheTimeout = 10 * time.Minute
} else {
cacheTimeout = 12 * time.Second
}

return pageData
return pageData, cacheTimeout
}
18 changes: 10 additions & 8 deletions handlers/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,15 @@ func Index(w http.ResponseWriter, r *http.Request) {
func getIndexPageData() *models.IndexPageData {
pageData := &models.IndexPageData{}
pageCacheKey := fmt.Sprintf("index")
if !utils.Config.Frontend.Debug && services.GlobalBeaconService.GetFrontendCache(pageCacheKey, pageData) == nil {
logrus.Printf("index page served from cache")
pageData = services.GlobalFrontendCache.ProcessCachedPage(pageCacheKey, true, pageData, func(pageCall *services.FrontendCacheProcessingPage) interface{} {
pageData, cacheTimeout := buildIndexPageData()
pageCall.CacheTimeout = cacheTimeout
return pageData
}
}).(*models.IndexPageData)
return pageData
}

func buildIndexPageData() (*models.IndexPageData, time.Duration) {
logrus.Printf("index page called")

recentEpochCount := 15
Expand Down Expand Up @@ -79,7 +84,7 @@ func getIndexPageData() *models.IndexPageData {
isSynced = true
}

pageData = &models.IndexPageData{
pageData := &models.IndexPageData{
NetworkName: utils.Config.Chain.Name,
DepositContract: utils.Config.Chain.Config.DepositContractAddress,
ShowSyncingMessage: !isSynced,
Expand Down Expand Up @@ -214,8 +219,5 @@ func getIndexPageData() *models.IndexPageData {
}
pageData.RecentBlockCount = uint64(len(pageData.RecentBlocks))

if pageCacheKey != "" {
services.GlobalBeaconService.SetFrontendCache(pageCacheKey, pageData, 12*time.Second)
}
return pageData
return pageData, 12 * time.Second
}
75 changes: 37 additions & 38 deletions handlers/slot.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,6 @@ func Slot(w http.ResponseWriter, r *http.Request) {
var notfoundTemplateFiles = append(layoutTemplateFiles,
"slot/notfound.html",
)
var errorTemplateFiles = append(layoutTemplateFiles,
"slot/error.html",
)
w.Header().Set("Content-Type", "text/html")

vars := mux.Vars(r)
Expand All @@ -55,13 +52,41 @@ func Slot(w http.ResponseWriter, r *http.Request) {
}
}

pageData := getSlotPageData(blockSlot, blockRootHash)
if pageData == nil {
data := InitPageData(w, r, "blockchain", "/slots", fmt.Sprintf("Slot %v", slotOrHash), notfoundTemplateFiles)
data.Data = "slot"
if handleTemplateError(w, r, "slot.go", "Slot", "notFound", templates.GetTemplate(notfoundTemplateFiles...).ExecuteTemplate(w, "layout", data)) != nil {
return // an error has occurred and was processed
}
return
}

template := templates.GetTemplate(slotTemplateFiles...)
data := InitPageData(w, r, "blockchain", "/slots", fmt.Sprintf("Slot %v", slotOrHash), slotTemplateFiles)
data.Data = pageData
if handleTemplateError(w, r, "index.go", "Slot", "", template.ExecuteTemplate(w, "layout", data)) != nil {
return // an error has occurred and was processed
}
}

func getSlotPageData(blockSlot int64, blockRoot []byte) *models.SlotPageData {
pageData := &models.SlotPageData{}
pageCacheKey := fmt.Sprintf("slot:%v:%x", blockSlot, blockRoot)
pageData = services.GlobalFrontendCache.ProcessCachedPage(pageCacheKey, true, pageData, func(pageCall *services.FrontendCacheProcessingPage) interface{} {
return buildSlotPageData(blockSlot, blockRoot)
}).(*models.SlotPageData)
return pageData
}

func buildSlotPageData(blockSlot int64, blockRoot []byte) *models.SlotPageData {
finalizedHead, err := services.GlobalBeaconService.GetFinalizedBlockHead()
var blockData *rpctypes.CombinedBlockResponse
if err == nil {
if blockSlot > -1 {
blockData, err = services.GlobalBeaconService.GetSlotDetailsBySlot(uint64(blockSlot), true)
} else {
blockData, err = services.GlobalBeaconService.GetSlotDetailsByBlockroot(blockRootHash, true)
blockData, err = services.GlobalBeaconService.GetSlotDetailsByBlockroot(blockRoot, true)
}
}

Expand All @@ -70,37 +95,19 @@ func Slot(w http.ResponseWriter, r *http.Request) {
if blockSlot > -1 {
dbBlocks := services.GlobalBeaconService.GetDbBlocksForSlots(uint64(blockSlot), 1, true)
if len(dbBlocks) > 0 {
blockRootHash = dbBlocks[0].Root
blockRoot = dbBlocks[0].Root
}
}
if blockRootHash != nil {
blockData = services.GlobalBeaconService.GetOrphanedBlock(blockRootHash)
if blockRoot != nil {
blockData = services.GlobalBeaconService.GetOrphanedBlock(blockRoot)
}
}

var slot uint64
if blockData == nil && err == nil {
if blockSlot > -1 {
slot = uint64(blockSlot)
} else {
data := InitPageData(w, r, "blockchain", "/slots", fmt.Sprintf("Slot %v", slotOrHash), notfoundTemplateFiles)
data.Data = "slot"
if handleTemplateError(w, r, "slot.go", "Slot", "notFound", templates.GetTemplate(notfoundTemplateFiles...).ExecuteTemplate(w, "layout", data)) != nil {
return // an error has occurred and was processed
}
return
}
} else if err != nil {
logrus.Printf("slot page error: %v", err)
data := InitPageData(w, r, "blockchain", "/slots", fmt.Sprintf("Slot %v", slotOrHash), errorTemplateFiles)
data.Data = err.Error()
if handleTemplateError(w, r, "slot.go", "Slot", "notFound", templates.GetTemplate(errorTemplateFiles...).ExecuteTemplate(w, "layout", data)) != nil {
return // an error has occurred and was processed
}
return
} else {
slot = uint64(blockData.Header.Data.Header.Message.Slot)
if blockData == nil {
return nil
}
slot := uint64(blockData.Header.Data.Header.Message.Slot)
logrus.Printf("slot page called: %v", slot)

pageData := &models.SlotPageData{
Slot: slot,
Expand All @@ -117,9 +124,6 @@ func Slot(w http.ResponseWriter, r *http.Request) {
// we can safely continue here. the UI is prepared to work without epoch duties, but fields related to the duties are not shown
}

template := templates.GetTemplate(slotTemplateFiles...)
data := InitPageData(w, r, "blockchain", "/slots", fmt.Sprintf("Slot %v", slotOrHash), slotTemplateFiles)

if blockData == nil {
pageData.Status = uint16(models.SlotStatusMissed)

Expand All @@ -138,12 +142,7 @@ func Slot(w http.ResponseWriter, r *http.Request) {
pageData.Block = getSlotPageBlockData(blockData, assignments)
}

logrus.Printf("slot page called")
data.Data = pageData

if handleTemplateError(w, r, "index.go", "Slot", "", template.ExecuteTemplate(w, "layout", data)) != nil {
return // an error has occurred and was processed
}
return pageData
}

func getSlotPageBlockData(blockData *rpctypes.CombinedBlockResponse, assignments *rpctypes.EpochAssignments) *models.SlotPageBlockData {
Expand Down
36 changes: 24 additions & 12 deletions handlers/slots.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,17 @@ func Slots(w http.ResponseWriter, r *http.Request) {
func getSlotsPageData(firstSlot uint64, pageSize uint64) *models.SlotsPageData {
pageData := &models.SlotsPageData{}
pageCacheKey := fmt.Sprintf("slots:%v:%v", firstSlot, pageSize)
if !utils.Config.Frontend.Debug && services.GlobalBeaconService.GetFrontendCache(pageCacheKey, pageData) == nil {
logrus.Printf("slots page served from cache: %v:%v", firstSlot, pageSize)
pageData = services.GlobalFrontendCache.ProcessCachedPage(pageCacheKey, true, pageData, func(pageCall *services.FrontendCacheProcessingPage) interface{} {
pageData, cacheTimeout := buildSlotsPageData(firstSlot, pageSize)
pageCall.CacheTimeout = cacheTimeout
return pageData
}
}).(*models.SlotsPageData)
return pageData
}

func buildSlotsPageData(firstSlot uint64, pageSize uint64) (*models.SlotsPageData, time.Duration) {
logrus.Printf("slots page called: %v:%v", firstSlot, pageSize)
pageData := &models.SlotsPageData{}

now := time.Now()
currentSlot := utils.TimeToSlot(uint64(now.Unix()))
Expand Down Expand Up @@ -181,19 +187,25 @@ func getSlotsPageData(firstSlot uint64, pageSize uint64) *models.SlotsPageData {
pageData.FirstSlot = firstSlot
pageData.LastSlot = lastSlot

if pageCacheKey != "" {
var cacheTimeout time.Duration
if firstEpoch < uint64(currentEpoch) {
cacheTimeout = 10 * time.Minute
} else {
cacheTimeout = 12 * time.Second
}
services.GlobalBeaconService.SetFrontendCache(pageCacheKey, pageData, cacheTimeout)
var cacheTimeout time.Duration
if firstEpoch < uint64(currentEpoch) {
cacheTimeout = 10 * time.Minute
} else {
cacheTimeout = 12 * time.Second
}
return pageData
return pageData, cacheTimeout
}

func getSlotsPageDataWithGraffitiFilter(graffiti string, pageIdx uint64, pageSize uint64) *models.SlotsPageData {
pageData := &models.SlotsPageData{}
pageCacheKey := fmt.Sprintf("slots:%v:%v:g-%v", pageIdx, pageSize, graffiti)
pageData = services.GlobalFrontendCache.ProcessCachedPage(pageCacheKey, true, pageData, func(_ *services.FrontendCacheProcessingPage) interface{} {
return buildSlotsPageDataWithGraffitiFilter(graffiti, pageIdx, pageSize)
}).(*models.SlotsPageData)
return pageData
}

func buildSlotsPageDataWithGraffitiFilter(graffiti string, pageIdx uint64, pageSize uint64) *models.SlotsPageData {
pageData := &models.SlotsPageData{
GraffitiFilter: graffiti,
}
Expand Down
22 changes: 12 additions & 10 deletions handlers/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,19 +73,24 @@ func Validator(w http.ResponseWriter, r *http.Request) {
}
}

func getValidatorPageData(validatorIndex uint64) *models.ValidatorPageData {
pageData := &models.ValidatorPageData{}
func getValidatorPageData(validatorIndex uint64) *models.EpochPageData {
pageData := &models.EpochPageData{}
pageCacheKey := fmt.Sprintf("validator:%v", validatorIndex)
if !utils.Config.Frontend.Debug && services.GlobalBeaconService.GetFrontendCache(pageCacheKey, pageData) == nil {
logrus.Printf("validator page served from cache: %v", validatorIndex)
pageData = services.GlobalFrontendCache.ProcessCachedPage(pageCacheKey, true, pageData, func(pageCall *services.FrontendCacheProcessingPage) interface{} {
pageData, cacheTimeout := buildValidatorPageData(validatorIndex)
pageCall.CacheTimeout = cacheTimeout
return pageData
}
}).(*models.EpochPageData)
return pageData
}

func buildValidatorPageData(validatorIndex uint64) (*models.ValidatorPageData, time.Duration) {
logrus.Printf("validator page called: %v", validatorIndex)

validatorSetRsp := services.GlobalBeaconService.GetCachedValidatorSet()
validator := validatorSetRsp.Data[validatorIndex]

pageData = &models.ValidatorPageData{
pageData := &models.ValidatorPageData{
CurrentEpoch: uint64(utils.TimeToEpoch(time.Now())),
Index: uint64(validator.Index),
Name: services.GlobalBeaconService.GetValidatorName(uint64(validator.Index)),
Expand Down Expand Up @@ -167,8 +172,5 @@ func getValidatorPageData(validatorIndex uint64) *models.ValidatorPageData {
}
pageData.RecentBlockCount = uint64(len(pageData.RecentBlocks))

if pageCacheKey != "" {
services.GlobalBeaconService.SetFrontendCache(pageCacheKey, pageData, 10*time.Minute)
}
return pageData
return pageData, 10 * time.Minute
}
Loading

0 comments on commit f44a1d0

Please sign in to comment.