【问题标题】:Pivotal GemFire cannot see cached data in Gfsh or PulsePivotal GemFire 无法看到 Gfsh 或 Pulse 中的缓存数据
【发布时间】:2018-08-03 05:50:10
【问题描述】:

我创建了一个带有 Geode/GemFire 缓存的 Spring Boot 应用程序。我想用我的 Spring Boot 应用程序连接到 Gfsh 创建的区域。在我的application-context.xml 中,我使用的是gfe:lookup-region,其 id 为 Gfsh 创建的区域。

在我的 Java 配置文件中,我使用 LookupRegionFactoryBean 来获取对外部定义区域的引用。

在我的SpringBootApplication 引导类中,我成功写入了我的存储库,因为我可以读回我保存的所有对象。但是使用 Gfsh 工具或 Pulse 工具时,我看不到我的缓存数据记录(或我保存的记录数。)

您能在这里提供一些见解吗?另外,我也尝试在我的配置文件中使用LocalRegionFactoryBean,但这种方法也不起作用。

谢谢。

    application-context.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
           xmlns:gfe-data="http://www.springframework.org/schema/data/gemfire"
           xmlns:gfe="http://www.springframework.org/schema/gemfire"
           xmlns:util="http://www.springframework.org/schema/util"
           xsi:schemaLocation="http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/data/gemfire http://www.springframework.org/schema/data/gemfire/spring-data-gemfire.xsd http://www.springframework.org/schema/gemfire http://www.springframework.org/schema/gemfire/spring-gemfire.xsd">

        <context:component-scan base-package="com.example.geode"></context:component-scan>

        <util:properties id="gemfireProperties" location="context:geode.properties"/>

    <!--    <context:property-placeholder location="context:geode.properties"/>

        <bean id="log-level"><property name="log-level" value="${log-level}"/></bean>
        <bean id="mcast-port"><property name="mcast-port" value="${mcast-port}"/></bean>
        <bean id="name"><property name="name" value="${name}"/></bean>-->

        <gfe:annotation-driven/>
        <gfe-data:function-executions base-package="com.example.geode.config"/>
        <!-- Declare GemFire Cache -->
    <!--    <gfe:cache/>    -->
        <gfe:cache properties-ref="gemfireProperties"/>

        <!-- Local region for being used by the Message -->
    <!--    <gfe:replicated-region id="employee" value-constraint="com.example.geode.model.Employee" data-policy="REPLICATE"/>-->
        <gfe:lookup-region id="employee" value-constraint="com.example.geode.model.Employee" data-policy="REPLICATE"/>
    <!--        <gfe:local-region id="employee" value-constraint="com.example.geode.model.Employee" data-policy="REPLICATE"/>-->
        <!-- Search for GemFire repositories -->
        <gfe-data:repositories base-package="com.example.geode.repository"/>


    </beans>

    GeodeConfiguration.java:

    //imports not included

    @Configuration

    @ComponentScan
    @EnableCaching
    @EnableGemfireRepositories//(basePackages = "com.example.geode.repository")
    @EnableGemfireFunctions
    @EnableGemfireFunctionExecutions//(basePackages = "com.example.geode.function")

    @PropertySource("classpath:geode.properties")

    public class GeodeConfiguration {

        @Autowired
        private EmployeeRepository employeeRepository;

        @Autowired
        private FunctionExecution functionExecution;

        @Value("${log-level}") 
        private String loglevel;
        @Value("${mcast-port}") 
        private String mcastPort; 
        @Value("${name}")
        private String name;    

        Properties gemfireProperties() {

            Properties gemfireProperties = new Properties();
            gemfireProperties.setProperty(loglevel, loglevel);
            gemfireProperties.setProperty(mcastPort, mcastPort);
            gemfireProperties.setProperty(name, name);

            return gemfireProperties;
        }  

        @Bean
        CacheFactoryBean gemfireCache() {

            return new CacheFactoryBean();
        }

        @Bean
        GemfireCacheManager cacheManager() {

            GemfireCacheManager cacheManager = new GemfireCacheManager();
            try {
                CacheFactoryBean cacheFactory = gemfireCache();
                //gemfireProperties();
                //cacheFactory.setProperties(gemfireProperties());
                cacheManager.setCache(cacheFactory.getObject()); //gemfireCache().getObject());
            } catch (Exception ex) {
                ex.printStackTrace();
            }
            return cacheManager;
        }

        @Bean(name="employee")
        //@Autowired
        LookupRegionFactoryBean<String, Employee> getRegion(final GemFireCache cache) 
                throws Exception {

            //CacheTypeAwareRegionFactoryBean<String, Employee> region = new CacheTypeAwareRegionFactoryBean<>();//GenericRegionFactoryBean<> //LocalRegionFactoryBean<>();

            LookupRegionFactoryBean<String, Employee> region = new LookupRegionFactoryBean<>();//GenericRegionFactoryBean<> //LocalRegionFactoryBean<>();        

            region.setRegionName("employee");

            try {
                    region.setCache(gemfireCache().getObject());
            } catch (Exception e) {
                    e.printStackTrace();
            }        
            //region.setClose(false);
            region.setName("employee");    
            //region.setAsyncEventQueues(new AsyncEventQueue[]{gemfireQueue});       
            //region.setPersistent(false);
            //region.setDataPolicy(org.apache.geode.cache.DataPolicy.REPLICATE);  //PRELOADED);   //REPLICATE);  
            region.afterPropertiesSet();

            return region;
        }

    }

    BasicGeodeApplication.java:

    //imports not provided

    @EnableGemfireRepositories
    @SpringBootApplication

    @ComponentScan("com.example.geode")
    //@EnableCaching
    @EnableGemfireCaching
    @EnableEntityDefinedRegions(basePackageClasses = Employee.class)

    @SuppressWarnings("unused")
    //@CacheServerApplication(name = "server2", locators = "localhost[10334]",
    //    autoStartup = true, port = 41414)
    public class BasicGeodeApplication {

        @Autowired
        private EmployeeRepository employeeRepository;

        @Autowired
        private EmployeeService employeeService;

        private static ConfigurableApplicationContext context;

        public static void main(String[] args) {

            context = SpringApplication.run(BasicGeodeApplication.class, args);


            BasicGeodeApplication bga = new BasicGeodeApplication();

        }

        @Bean
        public ApplicationRunner run(EmployeeRepository employeeRepository) {

            return args -> {

                Employee bob = new Employee("Bob", 80.0);
                Employee sue = new Employee("Susan", 95.0);
                Employee jane = new Employee("Jane", 85.0);
                Employee jack = new Employee("Jack", 90.0);

                List<Employee> employees = Arrays.asList(bob, sue, jane, jack);
                employees.sort(Comparator.comparing(Employee::getName));

                for (Employee employee : employees) {

                    //employeeService.saveEmployee(employee);
                    employeeRepository.save(employee);
                }

                System.out.println("\nList of employees:");

                employees //Arrays.asList(bob.getName(), sue.getName(), jane.getName(), jack.getName());
                    .forEach(person -> System.out.println("\t" + employeeRepository.findByName(person.getName())));

                System.out.println("\nQuery salary greater than 80k:");

                stream(employeeRepository.findBySalaryGreaterThan(80.0).spliterator(), false)
                    .forEach(person -> System.out.println("\t" + person));

                System.out.println("\nQuery salary less than 95k:");

                stream(employeeRepository.findBySalaryLessThan(95.0).spliterator(), false)
                    .forEach(person -> System.out.println("\t" + person));

                System.out.println("\nQuery salary greater than 80k and less than 95k:");

                stream(employeeRepository.findBySalaryGreaterThanAndSalaryLessThan(80.0, 95.0).spliterator(), false)
                    .forEach(person -> System.out.println("\t" + person));

            };

        }


    @Service 
    class EmployeeService {   

        @Autowired
        private EmployeeRepository employeeRepository;

        @CachePut(cacheNames = "employee", key = "#id")
        //@PutMapping("/")
        void saveEmployee(Employee employee) {

            employeeRepository.save(employee);
        }

        Employee findEmployee(String name) {

            return null;
        }
        //employeeRepository.findByName(person.getName())));
    }

    } 

    EmployeeRepository.java:


    @Repository("employeeRepository")
    //@DependsOn("gemfireCache")
    public interface EmployeeRepository extends CrudRepository<Employee, String> {

        Employee findByName(String name);

        Iterable<Employee> findBySalaryGreaterThan(double salary);

        Iterable<Employee> findBySalaryLessThan(double salary);

        Iterable<Employee> findBySalaryGreaterThanAndSalaryLessThan(double salary1, double salary2);
    }



Employee.java:

// imports not included

@Entity
@Region("employee")
public class Employee implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)    
    @javax.persistence.Id
    private Long id;
    public String name;
    public double salary;

    protected Employee() {}

    @PersistenceConstructor
    public Employee(String name, double salary) {
        this.name = name;
        this.salary = salary;
    }

    @Override
    public String toString() {
        return name + " salary is: " + salary;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getSalary() {
        return salary;
    }

    public void setSalary(int salary) {
        this.salary = salary;
    }
}

【问题讨论】:

    标签: gemfire geode spring-data-gemfire


    【解决方案1】:

    如果您的 Spring Boot 应用程序在尝试查找后实际上正在使用在 Gfsh 中创建的区域,我会感到非常惊讶。运行应用程序后使用 GfshPulse 时看不到 Region(s) 中的数据这一事实也很明显。

    此外,从您的配置来看,您的 Spring Boot 应用程序是否正在加入以 Gfsh 启动的集群并不完全清楚,因为您尚未共享 geode.properties 文件的内容。

    注意:我们稍后会回到您的属性文件,因为您引用它的方式(即在 Spring Util 架构中 location 元素的 context: 属性中使用 context:)不是甚至正确。事实上,您的整个 XML 文件甚至都无效!没有 class 的 Bean 定义无效,除非它们是抽象

    您使用的是什么版本的 Spring Boot 和 Spring Data Geode/GemFire (SDG)?

    根据您的 XML 配置文件中的 Spring XML 模式引用判断,您使用的是 Spring 3.0!?您不应在架构位置声明中引用版本。不合格的架构版本将根据您在应用程序类路径中导入的 Spring JAR 进行版本控制(例如,使用 Maven)。

    无论如何,我问的原因是,我对 SDG 进行了许多更改,导致它在配置不明确或不完整的情况下快速失败(对于 instance)。 p>

    在您的情况下,如果区域不存在,查找将立即失败。而且,我很确定区域不存在,因为默认情况下,SDG disables Cluster Configuration 在对等缓存节点/应用程序上。因此,您在 Gfsh 中创建的所有区域都不能立即用于您的 Spring Boot 应用程序。

    那么,让我们来看一个简单的例子。我将主要使用 SDG 的新 annotation configuration model 与一些 Java 配置混合,以方便使用和方便。我鼓励您阅读 SDG 参考指南中的这一章,因为您的配置无处不在,而且我很确定您会混淆实际发生的情况。

    这是我的 Spring Boot,Apache Geode 应用程序...

    @SpringBootApplication
    @SuppressWarnings("unused")
    public class ClusterConfiguredGeodeServerApplication {
    
      public static void main(String[] args) {
        SpringApplication.run(ClusterConfiguredGeodeServerApplication.class, args);
      }
    
      @Bean
      ApplicationRunner runner(GemfireTemplate customersTemplate) {
    
        return args -> {
    
          Customer jonDoe = Customer.named("Jon Doe").identifiedBy(1L);
    
          customersTemplate.put(jonDoe.getId(), jonDoe);
        };
      }
    
      @PeerCacheApplication(name = "ClusterConfiguredGeodeServerApplication")
      @EnablePdx
      static class GeodeConfiguration {
    
        @Bean("Customers")
        LookupRegionFactoryBean<Long, Customer> customersRegion(GemFireCache gemfireCache) {
    
          LookupRegionFactoryBean<Long, Customer> customersRegion = new LookupRegionFactoryBean<>();
    
          customersRegion.setCache(gemfireCache);
    
          return customersRegion;
        }
    
        @Bean("CustomersTemplate")
        GemfireTemplate customersTemplate(@Qualifier("Customers") Region<?, ?> customers) {
          return new GemfireTemplate(customers);
        }
      }
    
      @Data
      @RequiredArgsConstructor(staticName = "named")
      static class Customer {
    
        @Id
        private Long id;
    
        @NonNull
        private String name;
    
        Customer identifiedBy(Long id) {
          this.id = id;
          return this;
        }
      }
    }
    

    我正在使用 Spring Data Lovelace RC1(其中包括 Spring Data for Apache Geode 2.1.0.RC1)。我也在使用 Spring Boot 2.0.3.RELEASE,它引入了核心 Spring Framework 5.0.7.RELEASE,全部在 Java 8 上。

    我省略了包和导入声明。

    我正在使用Project Lombok 来定义我的Customer 类。

    我有一个嵌套的 GeodeConfiguration 类来将 Spring Boot 应用程序配置为能够加入 Apache Geode 集群的“对等”Cache 成员。但是,它还不是任何集群的一部分!

    最后,我配置了一个“客户”区域,在 Spring 上下文中“查找”。

    当我启动这个应用程序时,它失败了,因为还没有定义“客户”区域,无论如何......

    Caused by: org.springframework.beans.factory.BeanInitializationException: Region [Customers] in Cache [GemFireCache[id = 2126876651; isClosing = false; isShutDownAll = false; created = Thu Aug 02 13:43:07 PDT 2018; server = false; copyOnRead = false; lockLease = 120; lockTimeout = 60]] not found
        at org.springframework.data.gemfire.ResolvableRegionFactoryBean.createRegion(ResolvableRegionFactoryBean.java:146) ~[spring-data-geode-2.1.0.RC1.jar:2.1.0.RC1]
        at org.springframework.data.gemfire.ResolvableRegionFactoryBean.afterPropertiesSet(ResolvableRegionFactoryBean.java:96) ~[spring-data-geode-2.1.0.RC1.jar:2.1.0.RC1]
        at org.springframework.data.gemfire.LookupRegionFactoryBean.afterPropertiesSet(LookupRegionFactoryBean.java:72) ~[spring-data-geode-2.1.0.RC1.jar:2.1.0.RC1]
        ...
    

    这是意料之中的!

    好的,我们进入 Gfsh 并启动一个集群。

    你知道你需要用一个服务器启动一个定位器来形成一个集群,对吧?其他尝试加入集群的潜在对等方使用定位器,以便他们可以首先定位集群。需要服务器才能创建“客户”区域,因为您无法在定位器上创建区域。

    $ echo $GEODE_HOME
    /Users/jblum/pivdev/apache-geode-1.6.0
    
    $ gfsh
        _________________________     __
       / _____/ ______/ ______/ /____/ /
      / /  __/ /___  /_____  / _____  / 
     / /__/ / ____/  _____/ / /    / /  
    /______/_/      /______/_/    /_/    1.6.0
    
    Monitor and Manage Apache Geode
    
    gfsh>start locator --name=LocaorOne --log-level=config
    Starting a Geode Locator in /Users/jblum/pivdev/lab/LocaorOne...
    ....
    Locator in /Users/jblum/pivdev/lab/LocaorOne on 10.0.0.121[10334] as LocaorOne is currently online.
    Process ID: 41758
    Uptime: 5 seconds
    Geode Version: 1.6.0
    Java Version: 1.8.0_152
    Log File: /Users/jblum/pivdev/lab/LocaorOne/LocaorOne.log
    JVM Arguments: -Dgemfire.enable-cluster-configuration=true -Dgemfire.load-cluster-configuration-from-dir=false -Dgemfire.log-level=config -Dgemfire.launcher.registerSignalHandlers=true -Djava.awt.headless=true -Dsun.rmi.dgc.server.gcInterval=9223372036854775806
    Class-Path: /Users/jblum/pivdev/apache-geode-1.6.0/lib/geode-core-1.6.0.jar:/Users/jblum/pivdev/apache-geode-1.6.0/lib/geode-dependencies.jar
    
    Successfully connected to: JMX Manager [host=10.0.0.121, port=1099]
    
    Cluster configuration service is up and running.
    
    gfsh>start server --name=ServerOne --log-level=config
    Starting a Geode Server in /Users/jblum/pivdev/lab/ServerOne...
    ...
    Server in /Users/jblum/pivdev/lab/ServerOne on 10.0.0.121[40404] as ServerOne is currently online.
    Process ID: 41785
    Uptime: 3 seconds
    Geode Version: 1.6.0
    Java Version: 1.8.0_152
    Log File: /Users/jblum/pivdev/lab/ServerOne/ServerOne.log
    JVM Arguments: -Dgemfire.default.locators=10.0.0.121[10334] -Dgemfire.start-dev-rest-api=false -Dgemfire.use-cluster-configuration=true -Dgemfire.log-level=config -XX:OnOutOfMemoryError=kill -KILL %p -Dgemfire.launcher.registerSignalHandlers=true -Djava.awt.headless=true -Dsun.rmi.dgc.server.gcInterval=9223372036854775806
    Class-Path: /Users/jblum/pivdev/apache-geode-1.6.0/lib/geode-core-1.6.0.jar:/Users/jblum/pivdev/apache-geode-1.6.0/lib/geode-dependencies.jar
    
    gfsh>list members
      Name    | Id
    --------- | --------------------------------------------------------------
    LocaorOne | 10.0.0.121(LocaorOne:41758:locator)<ec><v0>:1024 [Coordinator]
    ServerOne | 10.0.0.121(ServerOne:41785)<v1>:1025
    
    gfsh>list regions
    No Regions Found
    
    gfsh>create region --name=Customers --type=PARTITION --key-constraint=java.lang.Long --value-constraint=java.lang.Object
     Member   | Status
    --------- | ------------------------------------------
    ServerOne | Region "/Customers" created on "ServerOne"
    
    gfsh>list regions
    List of regions
    ---------------
    Customers
    
    gfsh>describe region --name=Customers
    ..........................................................
    Name            : Customers
    Data Policy     : partition
    Hosting Members : ServerOne
    
    Non-Default Attributes Shared By Hosting Members  
    
     Type  |    Name     | Value
    ------ | ----------- | ---------
    Region | size        | 0
           | data-policy | PARTITION
    

    现在,即使我再次运行 Spring Boot 应用程序,它仍然会失败并出现相同的异常...

    Caused by: org.springframework.beans.factory.BeanInitializationException: Region [Customers] in Cache [GemFireCache[id = 989520513; isClosing = false; isShutDownAll = false; created = Thu Aug 02 14:09:25 PDT 2018; server = false; copyOnRead = false; lockLease = 120; lockTimeout = 60]] not found
        at org.springframework.data.gemfire.ResolvableRegionFactoryBean.createRegion(ResolvableRegionFactoryBean.java:146) ~[spring-data-geode-2.1.0.RC1.jar:2.1.0.RC1]
        at org.springframework.data.gemfire.ResolvableRegionFactoryBean.afterPropertiesSet(ResolvableRegionFactoryBean.java:96) ~[spring-data-geode-2.1.0.RC1.jar:2.1.0.RC1]
        at org.springframework.data.gemfire.LookupRegionFactoryBean.afterPropertiesSet(LookupRegionFactoryBean.java:72) ~[spring-data-geode-2.1.0.RC1.jar:2.1.0.RC1]
        ...
    

    为什么?

    这是因为 1) Spring Boot,Apache Geode peer Cache 应用程序还不是集群的一部分,并且 2) 因为默认情况下,SDG 不允许 Spring 配置/引导的 Apache Geode peer Cache应用程序从集群(特别是从Cluster Configuration Service)获取它的配置,因此,我们必须配置/启用这两个东西。

    我们可以通过将@PeerCacheApplication 注释的locators 属性指定为localhost[10334] 来让我们的Spring Boot、Apache Geode peer Cache 应用程序加入集群。

    @PeerCacheApplication(name = "...", locators = "localhost[10334]")

    我们可以通过启用useClusterConfiguration 属性让我们的Spring Boot、Apache Geode 对等点Cache 应用程序从集群中获取其配置,我们通过将以下Configurer bean 定义添加到我们内部的静态@987654359 来实现@class,如下:

    @Bean
    PeerCacheConfigurer useClusterConfigurationConfigurer() {
      return (beanName, cacheFactoryBean) -> cacheFactoryBean.setUseClusterConfiguration(true);
    }
    

    现在,当我们再次运行 Spring Boot、Apache Geode peer Cache 应用程序时,我们会看到完全不同的输出。首先,看到我们的peer成员(app)获取集群配置...

    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <cache xmlns="http://geode.apache.org/schema/cache" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" copy-on-read="false" is-server="false" lock-lease="120" lock-timeout="60" search-timeout="300" version="1.0" xsi:schemaLocation="http://geode.apache.org/schema/cache http://geode.apache.org/schema/cache/cache-1.0.xsd">
    
    <region name="Customers">
        <region-attributes data-policy="partition">
          <key-constraint>java.lang.Long</key-constraint>
          <value-constraint>java.lang.Object</value-constraint>
        </region-attributes>
      </region>
    </cache>
    

    接下来,您可能已经注意到我启用了 PDX,使用 SDG 的 @EnablePdx 注释。这使我们可以轻松地序列化我们的应用程序域模型对象类型(例如Customer),而我们的类型不需要过度实现java.io.Serializable。无论如何,您不一定要实现java.io.Serializable 有几个原因。使用 SDG 的 @EnablePdx 使用 SDG 的 MappingPdxSerializer 实现,它甚至比 Apache Geode/Pivotal GemFire 自己的 ReflectionBasedAutoSerializer 强大得多。

    作为序列化应用程序类型(即Customer)的结果,您将看到此输出...

    14:26:48.322 [main] INFO  org.apache.geode.internal.cache.PartitionedRegion - Partitioned Region /Customers is created with prId=2
    Started ClusterConfiguredGeodeServerApplication in 4.223 seconds (JVM running for 5.574)
    14:26:48.966 [main] INFO  org.apache.geode.pdx.internal.PeerTypeRegistration - Adding new type: PdxType[dsid=0, typenum=14762571
            name=example.app.spring.cluster_config.server.ClusterConfiguredGeodeServerApplication$Customer
            fields=[
            id:Object:identity:0:idx0(relativeOffset)=0:idx1(vlfOffsetIndex)=-1
            name:String:1:1:idx0(relativeOffset)=0:idx1(vlfOffsetIndex)=1]]
    14:26:49.002 [main] INFO  org.apache.geode.pdx.internal.TypeRegistry - Caching PdxType[dsid=0, typenum=14762571
            name=example.app.spring.cluster_config.server.ClusterConfiguredGeodeServerApplication$Customer
            fields=[
            id:Object:identity:0:idx0(relativeOffset)=0:idx1(vlfOffsetIndex)=-1
            name:String:1:1:idx0(relativeOffset)=0:idx1(vlfOffsetIndex)=1]]
    

    我启用 PDX 的另一个原因是我不需要将 Customer 类添加到使用 Gfsh 开始的服务器(即“ServerOne”)。它还允许我查询“客户”区域并看到Customer“Jon Doe”已成功添加...

    gfsh>describe region --name=Customers
    ..........................................................
    Name            : Customers
    Data Policy     : partition
    Hosting Members : ServerOne
    
    Non-Default Attributes Shared By Hosting Members  
    
     Type  |    Name     | Value
    ------ | ----------- | ---------
    Region | size        | 1
           | data-policy | PARTITION
    
    
    gfsh>
    gfsh>query --query="SELECT c.name FROM /Customers c"
    Result : true
    Limit  : 100
    Rows   : 1
    
    Result
    -------
    Jon Doe
    

    宾果!成功!

    我什至不会开始讨论您的配置有什么问题。我恳请您 read the docs(和 Apache Geode 的 User Guide;即适当的部分),了解概念,查看 examplesguides,提出简洁的问题等。

    这里是示例源代码...

    https://github.com/jxblum/contacts-application/blob/master/configuration-example/src/main/java/example/app/spring/cluster_config/server/ClusterConfiguredGeodeServerApplication.java

    希望这会有所帮助!

    -j

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多