Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
apache
Iotdb
提交
523f4788
I
Iotdb
项目概览
apache
/
Iotdb
9 个月 前同步成功
通知
25
Star
3344
Fork
916
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
I
Iotdb
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
未验证
提交
523f4788
编写于
7月 30, 2023
作者:
P
Peng Junzhi
提交者:
GitHub
7月 30, 2023
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Remove unnecessary metrics and optimize allocation byte counting (#10738)
上级
ccec8845
变更
2
隐藏空白更改
内联
并排
Showing
2 changed file
with
72 addition
and
84 deletion
+72
-84
iotdb-core/metrics/interface/src/main/java/org/apache/iotdb/metrics/metricsets/jvm/JvmGcMetrics.java
...org/apache/iotdb/metrics/metricsets/jvm/JvmGcMetrics.java
+68
-80
iotdb-core/metrics/interface/src/main/java/org/apache/iotdb/metrics/utils/SystemMetric.java
...ain/java/org/apache/iotdb/metrics/utils/SystemMetric.java
+4
-4
未找到文件。
iotdb-core/metrics/interface/src/main/java/org/apache/iotdb/metrics/metricsets/jvm/JvmGcMetrics.java
浏览文件 @
523f4788
...
@@ -54,7 +54,7 @@ import java.util.concurrent.atomic.AtomicLong;
...
@@ -54,7 +54,7 @@ import java.util.concurrent.atomic.AtomicLong;
public
class
JvmGcMetrics
implements
IMetricSet
,
AutoCloseable
{
public
class
JvmGcMetrics
implements
IMetricSet
,
AutoCloseable
{
private
static
final
Logger
logger
=
LoggerFactory
.
getLogger
(
JvmGcMetrics
.
class
);
private
static
final
Logger
logger
=
LoggerFactory
.
getLogger
(
JvmGcMetrics
.
class
);
private
final
List
<
Runnable
>
notificationListenerCleanUpRunnables
=
new
CopyOnWriteArrayList
<>();
private
final
List
<
Runnable
>
notificationListenerCleanUpRunnables
=
new
CopyOnWriteArrayList
<>();
private
String
y
oungGenPoolName
;
private
String
firstY
oungGenPoolName
;
private
String
oldGenPoolName
;
private
String
oldGenPoolName
;
private
String
nonGenerationalMemoryPool
;
private
String
nonGenerationalMemoryPool
;
private
final
Map
<
String
,
AtomicLong
>
lastGcTotalDurationMap
=
new
ConcurrentHashMap
<>();
private
final
Map
<
String
,
AtomicLong
>
lastGcTotalDurationMap
=
new
ConcurrentHashMap
<>();
...
@@ -62,8 +62,8 @@ public class JvmGcMetrics implements IMetricSet, AutoCloseable {
...
@@ -62,8 +62,8 @@ public class JvmGcMetrics implements IMetricSet, AutoCloseable {
public
JvmGcMetrics
()
{
public
JvmGcMetrics
()
{
for
(
MemoryPoolMXBean
mbean
:
ManagementFactory
.
getMemoryPoolMXBeans
())
{
for
(
MemoryPoolMXBean
mbean
:
ManagementFactory
.
getMemoryPoolMXBeans
())
{
String
name
=
mbean
.
getName
();
String
name
=
mbean
.
getName
();
if
(
isYoungGenPool
(
name
))
{
if
(
is
First
YoungGenPool
(
name
))
{
y
oungGenPoolName
=
name
;
firstY
oungGenPoolName
=
name
;
}
else
if
(
isOldGenPool
(
name
))
{
}
else
if
(
isOldGenPool
(
name
))
{
oldGenPoolName
=
name
;
oldGenPoolName
=
name
;
}
else
if
(
isNonGenerationalHeapPool
(
name
))
{
}
else
if
(
isNonGenerationalHeapPool
(
name
))
{
...
@@ -98,12 +98,8 @@ public class JvmGcMetrics implements IMetricSet, AutoCloseable {
...
@@ -98,12 +98,8 @@ public class JvmGcMetrics implements IMetricSet, AutoCloseable {
}
}
}
}
private
static
boolean
isConcurrentPhase
(
String
cause
,
String
name
)
{
private
static
boolean
isFirstYoungGenPool
(
String
name
)
{
return
"No GC"
.
equals
(
cause
)
||
"Shenandoah Cycles"
.
equals
(
name
);
return
name
!=
null
&&
name
.
endsWith
(
"Eden Space"
);
}
private
static
boolean
isYoungGenPool
(
String
name
)
{
return
name
!=
null
&&
(
name
.
endsWith
(
"Eden Space"
)
||
name
.
endsWith
(
"Survivor Space"
));
}
}
private
static
boolean
isOldGenPool
(
String
name
)
{
private
static
boolean
isOldGenPool
(
String
name
)
{
...
@@ -142,26 +138,35 @@ public class JvmGcMetrics implements IMetricSet, AutoCloseable {
...
@@ -142,26 +138,35 @@ public class JvmGcMetrics implements IMetricSet, AutoCloseable {
liveDataSize
,
liveDataSize
,
AtomicLong:
:
get
);
AtomicLong:
:
get
);
AtomicLong
heapMemUsedPercentage
=
new
AtomicLong
(
calculateMemoryUsagePercentage
());
metricService
.
createAutoGauge
(
SystemMetric
.
JVM_GC_MEMORY_USED_PERCENT
.
toString
(),
MetricLevel
.
CORE
,
heapMemUsedPercentage
,
AtomicLong:
:
get
);
Counter
allocatedBytes
=
metricService
.
getOrCreateCounter
(
SystemMetric
.
JVM_GC_MEMORY_ALLOCATED_BYTES
.
toString
(),
MetricLevel
.
CORE
);
Counter
promotedBytes
=
Counter
promotedBytes
=
(
oldGenPoolName
==
null
)
(
oldGenPoolName
==
null
)
?
null
?
null
:
metricService
.
getOrCreateCounter
(
:
metricService
.
getOrCreateCounter
(
SystemMetric
.
JVM_GC_MEMORY_PROMOTED_BYTES
.
toString
(),
MetricLevel
.
CORE
);
SystemMetric
.
JVM_GC_MEMORY_PROMOTED_BYTES
.
toString
(),
MetricLevel
.
CORE
);
// start watching for GC notifications
Counter
nonGenAllocatedBytes
=
final
AtomicLong
heapPoolSizeAfterGc
=
new
AtomicLong
();
(
nonGenerationalMemoryPool
==
null
)
?
null
:
metricService
.
getOrCreateCounter
(
SystemMetric
.
JVM_GC_NON_GEN_MEMORY_ALLOCATED_BYTES
.
toString
(),
MetricLevel
.
CORE
);
Counter
oldGenAllocatedBytes
=
(
oldGenPoolName
==
null
)
?
null
:
metricService
.
getOrCreateCounter
(
SystemMetric
.
JVM_GC_OLD_MEMORY_ALLOCATED_BYTES
.
toString
(),
MetricLevel
.
CORE
);
Counter
youngGenAllocatedBytes
=
(
firstYoungGenPoolName
==
null
)
?
null
:
metricService
.
getOrCreateCounter
(
SystemMetric
.
JVM_GC_YOUNG_MEMORY_ALLOCATED_BYTES
.
toString
(),
MetricLevel
.
CORE
);
final
AtomicLong
firstYoungHeapPoolSizeAfterGc
=
new
AtomicLong
();
// long live heap pool includes old gen heap pool and non-generation heap pool.
final
AtomicLong
longLivedHeapPoolSizeAfterGc
=
new
AtomicLong
();
// start watching for GC notifications
for
(
GarbageCollectorMXBean
mbean
:
ManagementFactory
.
getGarbageCollectorMXBeans
())
{
for
(
GarbageCollectorMXBean
mbean
:
ManagementFactory
.
getGarbageCollectorMXBeans
())
{
if
(!(
mbean
instanceof
NotificationEmitter
))
{
if
(!(
mbean
instanceof
NotificationEmitter
))
{
continue
;
continue
;
...
@@ -194,16 +199,15 @@ public class JvmGcMetrics implements IMetricSet, AutoCloseable {
...
@@ -194,16 +199,15 @@ public class JvmGcMetrics implements IMetricSet, AutoCloseable {
previousTotal
.
set
(
total
);
previousTotal
.
set
(
total
);
}
}
String
timerName
;
if
(
isConcurrentPhase
(
gcCause
,
notificationInfo
.
getGcName
()))
{
timerName
=
"jvm_gc_concurrent_phase_time"
;
}
else
{
timerName
=
"jvm_gc_pause"
;
}
// create a timer with tags named by gcCause, which binds gcCause with gcDuration
// create a timer with tags named by gcCause, which binds gcCause with gcDuration
Timer
timer
=
Timer
timer
=
metricService
.
getOrCreateTimer
(
metricService
.
getOrCreateTimer
(
timerName
,
MetricLevel
.
CORE
,
"action"
,
gcAction
,
"cause"
,
gcCause
);
SystemMetric
.
JVM_GC_PAUSE
.
toString
(),
MetricLevel
.
CORE
,
"action"
,
gcAction
,
"cause"
,
gcCause
);
timer
.
update
(
duration
,
TimeUnit
.
MILLISECONDS
);
timer
.
update
(
duration
,
TimeUnit
.
MILLISECONDS
);
// add support for ZGC
// add support for ZGC
...
@@ -219,25 +223,6 @@ public class JvmGcMetrics implements IMetricSet, AutoCloseable {
...
@@ -219,25 +223,6 @@ public class JvmGcMetrics implements IMetricSet, AutoCloseable {
pausesCount
.
inc
();
pausesCount
.
inc
();
}
}
// monitoring old/young GC count, which is helpful for users to locate GC exception.
// Unfortunately, the JMX doesn't seem to provide an api for monitoring mixed gc in G1.
// In fact, JMX may treat mixed GCs as minor GCs.
if
(
GcGenerationAge
.
fromName
(
notificationInfo
.
getGcName
())
==
GcGenerationAge
.
OLD
)
{
Counter
oldGcCounter
=
metricService
.
getOrCreateCounter
(
SystemMetric
.
JVM_GC_YOUNG_GC_COUNT
.
toString
(),
MetricLevel
.
CORE
);
oldGcCounter
.
inc
();
}
else
if
(
GcGenerationAge
.
fromName
(
notificationInfo
.
getGcName
())
==
GcGenerationAge
.
YOUNG
)
{
Counter
youngGcCounter
=
metricService
.
getOrCreateCounter
(
SystemMetric
.
JVM_GC_OLD_GC_COUNT
.
toString
(),
MetricLevel
.
CORE
);
youngGcCounter
.
inc
();
}
// update memory usage percentage
heapMemUsedPercentage
.
set
(
calculateMemoryUsagePercentage
());
// Update promotion and allocation counters
// Update promotion and allocation counters
final
Map
<
String
,
MemoryUsage
>
before
=
gcInfo
.
getMemoryUsageBeforeGc
();
final
Map
<
String
,
MemoryUsage
>
before
=
gcInfo
.
getMemoryUsageBeforeGc
();
final
Map
<
String
,
MemoryUsage
>
after
=
gcInfo
.
getMemoryUsageAfterGc
();
final
Map
<
String
,
MemoryUsage
>
after
=
gcInfo
.
getMemoryUsageAfterGc
();
...
@@ -246,8 +231,8 @@ public class JvmGcMetrics implements IMetricSet, AutoCloseable {
...
@@ -246,8 +231,8 @@ public class JvmGcMetrics implements IMetricSet, AutoCloseable {
countPoolSizeDelta
(
countPoolSizeDelta
(
gcInfo
.
getMemoryUsageBeforeGc
(),
gcInfo
.
getMemoryUsageBeforeGc
(),
gcInfo
.
getMemoryUsageAfterGc
(),
gcInfo
.
getMemoryUsageAfterGc
(),
a
llocatedBytes
,
nonGenA
llocatedBytes
,
h
eapPoolSizeAfterGc
,
longLivedH
eapPoolSizeAfterGc
,
nonGenerationalMemoryPool
);
nonGenerationalMemoryPool
);
if
(
after
.
get
(
nonGenerationalMemoryPool
).
getUsed
()
if
(
after
.
get
(
nonGenerationalMemoryPool
).
getUsed
()
<
before
.
get
(
nonGenerationalMemoryPool
).
getUsed
())
{
<
before
.
get
(
nonGenerationalMemoryPool
).
getUsed
())
{
...
@@ -272,8 +257,7 @@ public class JvmGcMetrics implements IMetricSet, AutoCloseable {
...
@@ -272,8 +257,7 @@ public class JvmGcMetrics implements IMetricSet, AutoCloseable {
// GC (since in JMX, a minor GC of G1 may actually represent mixed GC, which collect
// GC (since in JMX, a minor GC of G1 may actually represent mixed GC, which collect
// some obj in old gen region). To track the
// some obj in old gen region). To track the
// live data size we record the value if we see a reduction in the old gen heap size
// live data size we record the value if we see a reduction in the old gen heap size
// or
// or after a major GC.
// after a major GC.
if
(
oldAfter
<
oldBefore
if
(
oldAfter
<
oldBefore
||
GcGenerationAge
.
fromName
(
notificationInfo
.
getGcName
())
||
GcGenerationAge
.
fromName
(
notificationInfo
.
getGcName
())
==
GcGenerationAge
.
OLD
)
{
==
GcGenerationAge
.
OLD
)
{
...
@@ -281,15 +265,21 @@ public class JvmGcMetrics implements IMetricSet, AutoCloseable {
...
@@ -281,15 +265,21 @@ public class JvmGcMetrics implements IMetricSet, AutoCloseable {
final
long
oldMaxAfter
=
after
.
get
(
oldGenPoolName
).
getMax
();
final
long
oldMaxAfter
=
after
.
get
(
oldGenPoolName
).
getMax
();
maxDataSize
.
set
(
oldMaxAfter
);
maxDataSize
.
set
(
oldMaxAfter
);
}
}
countPoolSizeDelta
(
gcInfo
.
getMemoryUsageBeforeGc
(),
gcInfo
.
getMemoryUsageAfterGc
(),
oldGenAllocatedBytes
,
longLivedHeapPoolSizeAfterGc
,
oldGenPoolName
);
}
}
if
(
y
oungGenPoolName
!=
null
)
{
if
(
firstY
oungGenPoolName
!=
null
)
{
countPoolSizeDelta
(
countPoolSizeDelta
(
gcInfo
.
getMemoryUsageBeforeGc
(),
gcInfo
.
getMemoryUsageBeforeGc
(),
gcInfo
.
getMemoryUsageAfterGc
(),
gcInfo
.
getMemoryUsageAfterGc
(),
a
llocatedBytes
,
youngGenA
llocatedBytes
,
h
eapPoolSizeAfterGc
,
firstYoungH
eapPoolSizeAfterGc
,
y
oungGenPoolName
);
firstY
oungGenPoolName
);
}
}
}
}
};
};
...
@@ -321,12 +311,22 @@ public class JvmGcMetrics implements IMetricSet, AutoCloseable {
...
@@ -321,12 +311,22 @@ public class JvmGcMetrics implements IMetricSet, AutoCloseable {
metricService
.
remove
(
MetricType
.
AUTO_GAUGE
,
SystemMetric
.
JVM_GC_MAX_DATA_SIZE_BYTES
.
toString
());
metricService
.
remove
(
MetricType
.
AUTO_GAUGE
,
SystemMetric
.
JVM_GC_MAX_DATA_SIZE_BYTES
.
toString
());
metricService
.
remove
(
metricService
.
remove
(
MetricType
.
AUTO_GAUGE
,
SystemMetric
.
JVM_GC_LIVE_DATA_SIZE_BYTES
.
toString
());
MetricType
.
AUTO_GAUGE
,
SystemMetric
.
JVM_GC_LIVE_DATA_SIZE_BYTES
.
toString
());
metricService
.
remove
(
MetricType
.
COUNTER
,
SystemMetric
.
JVM_GC_MEMORY_ALLOCATED_BYTES
.
toString
());
metricService
.
remove
(
MetricType
.
AUTO_GAUGE
,
SystemMetric
.
JVM_GC_MEMORY_USED_PERCENT
.
toString
());
if
(
oldGenPoolName
!=
null
)
{
if
(
nonGenerationalMemoryPool
!=
null
)
{
metricService
.
remove
(
metricService
.
remove
(
MetricType
.
COUNTER
,
SystemMetric
.
JVM_GC_MEMORY_PROMOTED_BYTES
.
toString
());
MetricType
.
COUNTER
,
SystemMetric
.
JVM_GC_NON_GEN_MEMORY_ALLOCATED_BYTES
.
toString
());
}
else
{
if
(
oldGenPoolName
!=
null
)
{
metricService
.
remove
(
MetricType
.
COUNTER
,
SystemMetric
.
JVM_GC_MEMORY_PROMOTED_BYTES
.
toString
());
metricService
.
remove
(
MetricType
.
COUNTER
,
SystemMetric
.
JVM_GC_OLD_MEMORY_ALLOCATED_BYTES
.
toString
());
}
if
(
firstYoungGenPoolName
!=
null
)
{
metricService
.
remove
(
MetricType
.
COUNTER
,
SystemMetric
.
JVM_GC_YOUNG_MEMORY_ALLOCATED_BYTES
.
toString
());
}
}
}
// start watching for GC notifications
// start watching for GC notifications
...
@@ -342,13 +342,14 @@ public class JvmGcMetrics implements IMetricSet, AutoCloseable {
...
@@ -342,13 +342,14 @@ public class JvmGcMetrics implements IMetricSet, AutoCloseable {
String
gcCause
=
notificationInfo
.
getGcCause
();
String
gcCause
=
notificationInfo
.
getGcCause
();
String
gcAction
=
notificationInfo
.
getGcAction
();
String
gcAction
=
notificationInfo
.
getGcAction
();
String
timerName
;
metricService
.
remove
(
if
(
isConcurrentPhase
(
gcCause
,
notificationInfo
.
getGcName
()))
{
MetricType
.
TIMER
,
timerName
=
"jvm_gc_concurrent_phase_time"
;
SystemMetric
.
JVM_GC_PAUSE
.
toString
(),
}
else
{
"action"
,
timerName
=
"jvm_gc_pause"
;
gcAction
,
}
"cause"
,
metricService
.
remove
(
MetricType
.
TIMER
,
timerName
,
"action"
,
gcAction
,
"cause"
,
gcCause
);
gcCause
);
if
(
mbean
.
getName
().
equals
(
"ZGC Cycles"
))
{
if
(
mbean
.
getName
().
equals
(
"ZGC Cycles"
))
{
metricService
.
remove
(
metricService
.
remove
(
MetricType
.
COUNTER
,
SystemMetric
.
JVM_ZGC_CYCLES_COUNT
.
toString
());
MetricType
.
COUNTER
,
SystemMetric
.
JVM_ZGC_CYCLES_COUNT
.
toString
());
...
@@ -356,13 +357,6 @@ public class JvmGcMetrics implements IMetricSet, AutoCloseable {
...
@@ -356,13 +357,6 @@ public class JvmGcMetrics implements IMetricSet, AutoCloseable {
metricService
.
remove
(
metricService
.
remove
(
MetricType
.
COUNTER
,
SystemMetric
.
JVM_ZGC_PAUSES_COUNT
.
toString
());
MetricType
.
COUNTER
,
SystemMetric
.
JVM_ZGC_PAUSES_COUNT
.
toString
());
}
}
if
(
GcGenerationAge
.
fromName
(
notificationInfo
.
getGcName
())
==
GcGenerationAge
.
OLD
)
{
metricService
.
remove
(
MetricType
.
COUNTER
,
SystemMetric
.
JVM_GC_YOUNG_GC_COUNT
.
toString
());
}
else
if
(
GcGenerationAge
.
fromName
(
notificationInfo
.
getGcName
())
==
GcGenerationAge
.
YOUNG
)
{
metricService
.
remove
(
MetricType
.
COUNTER
,
SystemMetric
.
JVM_GC_OLD_GC_COUNT
.
toString
());
}
};
};
NotificationEmitter
notificationEmitter
=
(
NotificationEmitter
)
mbean
;
NotificationEmitter
notificationEmitter
=
(
NotificationEmitter
)
mbean
;
notificationEmitter
.
addNotificationListener
(
notificationEmitter
.
addNotificationListener
(
...
@@ -426,12 +420,6 @@ public class JvmGcMetrics implements IMetricSet, AutoCloseable {
...
@@ -426,12 +420,6 @@ public class JvmGcMetrics implements IMetricSet, AutoCloseable {
notificationListenerCleanUpRunnables
.
forEach
(
Runnable:
:
run
);
notificationListenerCleanUpRunnables
.
forEach
(
Runnable:
:
run
);
}
}
public
long
calculateMemoryUsagePercentage
()
{
return
(
ManagementFactory
.
getMemoryMXBean
().
getHeapMemoryUsage
().
getUsed
()
*
100
/
Runtime
.
getRuntime
().
maxMemory
());
}
enum
GcGenerationAge
{
enum
GcGenerationAge
{
OLD
,
OLD
,
YOUNG
,
YOUNG
,
...
...
iotdb-core/metrics/interface/src/main/java/org/apache/iotdb/metrics/utils/SystemMetric.java
浏览文件 @
523f4788
...
@@ -79,13 +79,13 @@ public enum SystemMetric {
...
@@ -79,13 +79,13 @@ public enum SystemMetric {
JVM_THREADS_STATUS_THREADS
(
"jvm_threads_states_threads"
),
JVM_THREADS_STATUS_THREADS
(
"jvm_threads_states_threads"
),
JVM_GC_MAX_DATA_SIZE_BYTES
(
"jvm_gc_max_data_size_bytes"
),
JVM_GC_MAX_DATA_SIZE_BYTES
(
"jvm_gc_max_data_size_bytes"
),
JVM_GC_LIVE_DATA_SIZE_BYTES
(
"jvm_gc_live_data_size_bytes"
),
JVM_GC_LIVE_DATA_SIZE_BYTES
(
"jvm_gc_live_data_size_bytes"
),
JVM_GC_MEMORY_ALLOCATED_BYTES
(
"jvm_gc_memory_allocated_bytes"
),
JVM_GC_YOUNG_MEMORY_ALLOCATED_BYTES
(
"jvm_gc_young_memory_allocated_bytes"
),
JVM_GC_OLD_MEMORY_ALLOCATED_BYTES
(
"jvm_gc_old_memory_allocated_bytes"
),
JVM_GC_NON_GEN_MEMORY_ALLOCATED_BYTES
(
"jvm_gc_non_gen_memory_allocated_bytes"
),
JVM_GC_MEMORY_PROMOTED_BYTES
(
"jvm_gc_memory_promoted_bytes"
),
JVM_GC_MEMORY_PROMOTED_BYTES
(
"jvm_gc_memory_promoted_bytes"
),
JVM_GC_
MEMORY_USED_PERCENT
(
"jvm_gc_memory_used_percent
"
),
JVM_GC_
PAUSE
(
"jvm_gc_pause
"
),
JVM_ZGC_CYCLES_COUNT
(
"jvm_zgc_cycles_count"
),
JVM_ZGC_CYCLES_COUNT
(
"jvm_zgc_cycles_count"
),
JVM_ZGC_PAUSES_COUNT
(
"jvm_zgc_pauses_count"
),
JVM_ZGC_PAUSES_COUNT
(
"jvm_zgc_pauses_count"
),
JVM_GC_YOUNG_GC_COUNT
(
"jvm_gc_old_gc_count"
),
JVM_GC_OLD_GC_COUNT
(
"jvm_gc_young_gc_count"
),
JVM_GC_ACCUMULATED_TIME_PERCENTAGE
(
"jvm_gc_accumulated_time_percentage"
),
JVM_GC_ACCUMULATED_TIME_PERCENTAGE
(
"jvm_gc_accumulated_time_percentage"
),
// net related
// net related
RECEIVED_BYTES
(
"received_bytes"
),
RECEIVED_BYTES
(
"received_bytes"
),
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录