This is an automated email from the ASF dual-hosted git repository.

guangning pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pulsar-manager.git


The following commit(s) were added to refs/heads/master by this push:
     new 2cffa68  [Offload] Add offload threshold input (#375)
2cffa68 is described below

commit 2cffa68d3d9aebe77f8652abe30c447567ff57d3
Author: ran <[email protected]>
AuthorDate: Thu Mar 25 20:11:07 2021 +0800

    [Offload] Add offload threshold input (#375)
    
    Fixes #374
    
    ### Motivation
    
    Currently, the offload operation lacks the offload threshold.
    
    ### Modifications
    
    Add the offload threshold input for the offload operation.
    
    ### Verifying this change
    
    - [ ] Make sure that the change passes the `./gradlew build` checks.
---
 front-end/src/lang/en.js                        |   6 +-
 front-end/src/lang/zh.js                        |   6 +-
 front-end/src/utils/validate.js                 |  25 ++++++
 front-end/src/views/management/topics/topic.vue | 113 +++++++++++++++++++-----
 4 files changed, 125 insertions(+), 25 deletions(-)

diff --git a/front-end/src/lang/en.js b/front-end/src/lang/en.js
index 23f566e..f2c974f 100644
--- a/front-end/src/lang/en.js
+++ b/front-end/src/lang/en.js
@@ -619,11 +619,15 @@ export default {
       unloadTopicSuccess: 'Successfully unload the topic!',
       terminateTopicSuccess: 'Successfully terminate the topic!',
       startCompactionSuccess: 'Successfully start compacting the topic!',
-      startOffloadSuccess: 'Successfully start offloading the topic!',
+      startOffloadSuccess: 'Successfully start offloading the topic',
       expireMessageSuccess: 'Successfully expire messages the topic!',
       resetMessageSuccess: 'Successfully reset messages the topic!',
       clearMessageSuccess: 'Successfully clear messages the topic'
     },
+    errorLog: {
+      noOffloadData: 'Nothing to offload!',
+      invalidSizeStr: 'Invalid size string! (e.g 200K 50M 1G)'
+    },
     info: 'INFO',
     column: 'column',
     data: 'data',
diff --git a/front-end/src/lang/zh.js b/front-end/src/lang/zh.js
index bbec239..db9b299 100644
--- a/front-end/src/lang/zh.js
+++ b/front-end/src/lang/zh.js
@@ -619,9 +619,13 @@ export default {
       unloadTopicSuccess: 'Successfully unload the topic!',
       terminateTopicSuccess: 'Successfully terminate the topic!',
       startCompactionSuccess: 'Successfully start compacting the topic!',
-      startOffloadSuccess: 'Successfully start offloading the topic!',
+      startOffloadSuccess: 'Successfully start offloading the topic',
       expireMessageSuccess: 'Successfully expire messages the topic!'
     },
+    errorLog: {
+      noOffloadData: 'Nothing to offload!',
+      invalidSizeStr: 'Invalid size string! (e.g 200K 50M 1G)'
+    },
     info: 'INFO',
     column: 'column',
     data: 'data',
diff --git a/front-end/src/utils/validate.js b/front-end/src/utils/validate.js
index c45458a..751bb12 100644
--- a/front-end/src/utils/validate.js
+++ b/front-end/src/utils/validate.js
@@ -86,3 +86,28 @@ export function validateServiceUrl(expectedProtocol, 
allowEmpty) {
     }
   }
 }
+
+export function validateSizeString(str) {
+  var last = str.charAt(str.length - 1)
+  var subStr = str.substring(0, str.length - 1)
+  switch (last) {
+    case 'k':
+    case 'K':
+      return Number(subStr) * 1024
+
+    case 'm':
+    case 'M':
+      return Number(subStr) * 1024 * 1024
+
+    case 'g':
+    case 'G':
+      return Number(subStr) * 1024 * 1024 * 1024
+
+    case 't':
+    case 'T':
+      return Number(subStr) * 1024 * 1024 * 1024 * 1024
+
+    default:
+      return Number(str)
+  }
+}
diff --git a/front-end/src/views/management/topics/topic.vue 
b/front-end/src/views/management/topics/topic.vue
index 1d211c9..f45b53b 100644
--- a/front-end/src/views/management/topics/topic.vue
+++ b/front-end/src/views/management/topics/topic.vue
@@ -185,23 +185,29 @@
                 class="circle">
                 <span class="circle-font">{{ offload }}</span>
               </el-button>
-              <el-button
-                v-if="offload !== 'RUNNING'"
-                type="primary"
-                
style="display:block;margin-top:15px;margin-left:auto;margin-right:auto;"
-                icon="el-icon-refresh"
-                @click="handleOffload">
-                {{ $t('topic.offload') }}
-              </el-button>
-              <el-button
-                v-if="offload === 'RUNNING'"
-                type="success"
-                
style="display:block;margin-top:15px;margin-left:auto;margin-right:auto;"
-                icon="el-icon-refresh"
-                disabled
-                @click="handleOffload">
-                {{ $t('topic.offload') }}
-              </el-button>
+              <el-row type="flex" justify="center" style="margin-top:15px;">
+                <el-col :span="16">
+                  <el-button
+                    :disabled="offloadDisabled"
+                    type="primary"
+                    icon="el-icon-refresh"
+                    @click="handleOffload">
+                    {{ $t('topic.offload') }}
+                  </el-button>
+                </el-col>
+                <el-col :span="8">
+                  <el-tooltip
+                    class="item"
+                    effect="dark"
+                    content="offload threshold (e.g 200k 50m 1g)"
+                    placement="top-start">
+                    <el-input
+                      v-model="offloadThreshold"
+                      :disabled="offloadDisabled"
+                      style="display:block;"/>
+                  </el-tooltip>
+                </el-col>
+              </el-row>
             </el-card>
           </el-col>
         </el-row>
@@ -554,6 +560,7 @@ import Pagination from '@/components/Pagination' // 
Secondary package based on e
 import { formatBytes } from '@/utils/index'
 import { numberFormatter } from '@/filters/index'
 import { putSubscriptionOnCluster, deleteSubscriptionOnCluster } from 
'@/api/subscriptions'
+import { validateSizeString } from '@/utils/validate'
 
 const defaultForm = {
   persistent: '',
@@ -645,7 +652,9 @@ export default {
       routeTopic: '',
       routeTopicPartition: -1,
       routeCluster: '',
-      loaded: false
+      loaded: false,
+      offloadThreshold: '0K',
+      offloadDisabled: true
     }
   },
   created() {
@@ -739,6 +748,7 @@ export default {
       offloadStatusOnCluster(this.getCurrentCluster(), 
this.postForm.persistent, this.getFullTopic()).then(response => {
         if (!response.data) return
         this.offload = response.data.status
+        this.offloadDisabled = this.offload === 'RUNNING'
       })
     },
     getCompactionStatus() {
@@ -1026,15 +1036,72 @@ export default {
       })
     },
     handleOffload() {
-      offloadOnCluster(this.getCurrentCluster(), this.postForm.persistent, 
this.getFullTopic()).then(response => {
+      var threshold = validateSizeString(this.offloadThreshold)
+      if (isNaN(threshold) || threshold < 0) {
         this.$notify({
-          title: 'success',
-          message: this.$i18n.t('topic.notification.startOffloadSuccess'),
-          type: 'success',
+          title: 'error',
+          message: this.$i18n.t('topic.errorLog.invalidSizeStr'),
+          type: 'error',
           duration: 3000
         })
+        return
+      }
+
+      fetchTopicStatsInternal(this.postForm.persistent, 
this.getFullTopic()).then(response => {
+        let ledgers = response.data.ledgers
+
+        if (!ledgers || ledgers.length <= 1) {
+          this.$notify({
+            title: 'warn',
+            message: this.$i18n.t('topic.errorLog.noOffloadData'),
+            type: 'warn',
+            duration: 3000
+          })
+          return
+        }
+
+        ledgers[ledgers.length - 1].size = response.data.currentLedgerSize
+        ledgers = ledgers.reverse()
+
+        var totalSize = 0
+        var preLedgerId = ledgers[0].ledgerId
+        var messageId
+        for (var i = 0; i < ledgers.length; i++) {
+          totalSize += ledgers[i].size
+          if (totalSize > threshold) {
+            messageId = {
+              ledgerId: preLedgerId,
+              entryId: 0,
+              partitionIndex: -1
+            }
+            break
+          }
+          preLedgerId = ledgers[i].ledgerId
+        }
+
+        if (!messageId) {
+          this.$notify({
+            title: 'warn',
+            message: this.$i18n.t('topic.errorLog.noOffloadData'),
+            type: 'warn',
+            duration: 3000
+          })
+          return
+        }
+
+        offloadOnCluster(this.getCurrentCluster(), this.postForm.persistent, 
this.getFullTopic(), messageId)
+          .then(response => {
+            var msg = this.$i18n.t('topic.notification.startOffloadSuccess') +
+                        ' before ' + messageId['ledgerId'] + ':' + 
messageId['entryId'] + ' !'
+            this.$notify({
+              title: 'success',
+              message: msg,
+              type: 'success',
+              duration: 3000
+            })
+          })
+        this.getOffloadStatus()
       })
-      this.getOffloadStatus()
     },
     handleDeleteTopic() {
       this.dialogStatus = 'delete'

Reply via email to