কীভাবে অবজেক্ট ক্যাচিং কাজ করে?


21

আমি এখানে একটি নির্দিষ্ট উত্তর খুঁজছি। যখন অবজেক্ট ক্যাচিং সক্ষম করা থাকে, বিকল্প এবং স্থানান্তরগুলি কোথায় জীবনযাপন করে?

ডিফল্টরূপে, উভয়ই ডাটাবেজে সঞ্চিত থাকে। তবে আমি কিছু রেফারেন্স শুনেছি যে মেমক্যাচ সেগুলি অন্য কোথাও সংরক্ষণ করবে এবং এপিসি পুরোপুরি অন্য কিছু করবে। কোথায়, ঠিক , এই তথ্য উভয় ক্ষেত্রেই অবিচল থাকবে?


2
@ টসচো উল্লেখ করা নিবন্ধটি এখন আর্কাইভ.অর্গে
এখানে

উত্তর:


34

ওয়ার্ডপ্রেস, ডিফল্টরূপে "অবজেক্ট ক্যাচিং" রূপ দেয় তবে এর আজীবন কেবলমাত্র একটি পৃষ্ঠার বোঝা।

বিকল্পগুলি আসলে এটির একটি ভাল উদাহরণ। পরীক্ষা করে দেখুন এই উত্তরটি আরও তথ্যের জন্য। সংক্ষিপ্ত:

  1. একটি পৃষ্ঠা শুরু হয়
  2. সমস্ত বিকল্প একটি সাধারণ SELECT option_name, option_value from $wpdb->optionsবিবৃতি দিয়ে লোড করা হয়
  3. পরবর্তীকালে এই বিকল্পগুলির জন্য অনুরোধগুলি (যেমন get_optionডাব্লু ডাটাবেসটিকে কখনই আঘাত করবে না কারণ তারা ডাব্লুপি ক্যাশে এপিআই দিয়ে সঞ্চিত রয়েছে)

বিকল্পগুলি ডেটাবেজে সর্বদা "লাইভ" থাকে এবং সেখানে সর্বদা অবিচল থাকে - এটি তাদের "আধ্যাত্মিক" উত্স। এটি বলেছিল, অপশনগুলি বস্তু ক্যাশে লোড করা হয় তাই আপনি যখন কোনও বিকল্পের জন্য অনুরোধ করেন তখন সেখানে 99% সম্ভাবনা থাকে যে অনুরোধটি কখনই ডাটাবেসে আঘাত হানে না।

স্থানান্তরগুলি কিছুটা আলাদা।

ওয়ার্ডপ্রেস আপনাকে ক্যাশে এপিআইকে একটি ড্রপ-ইন - আপনার ফাইলগুলিতে সরাসরি স্থান দেয় এমন একটি ফাইল দিয়ে প্রতিস্থাপন করতে দেয় wp-content। আপনি যদি নিজের নিজস্ব ক্যাশে ড্রপ তৈরি করেন বা বিদ্যমান প্লাগইন ব্যবহার করেন তবে আপনি কোনও একক পৃষ্ঠার লোডের চেয়ে অবজেক্টের ক্যাশে দীর্ঘতর রাখতে পারবেন। আপনি যখন এটি করেন, স্থানান্তরকারী, কিছুটা পরিবর্তন করুন।

আসুন set_transientফাংশনটি একবার দেখুন wp-includes/option.php

<?php
/**
 * Set/update the value of a transient.
 *
 * You do not need to serialize values. If the value needs to be serialized, then
 * it will be serialized before it is set.
 *
 * @since 2.8.0
 * @package WordPress
 * @subpackage Transient
 *
 * @uses apply_filters() Calls 'pre_set_transient_$transient' hook to allow overwriting the
 *  transient value to be stored.
 * @uses do_action() Calls 'set_transient_$transient' and 'setted_transient' hooks on success.
 *
 * @param string $transient Transient name. Expected to not be SQL-escaped.
 * @param mixed $value Transient value. Expected to not be SQL-escaped.
 * @param int $expiration Time until expiration in seconds, default 0
 * @return bool False if value was not set and true if value was set.
 */
function set_transient( $transient, $value, $expiration = 0 ) {
    global $_wp_using_ext_object_cache;

    $value = apply_filters( 'pre_set_transient_' . $transient, $value );

    if ( $_wp_using_ext_object_cache ) {
        $result = wp_cache_set( $transient, $value, 'transient', $expiration );
    } else {
        $transient_timeout = '_transient_timeout_' . $transient;
        $transient = '_transient_' . $transient;
        if ( false === get_option( $transient ) ) {
            $autoload = 'yes';
            if ( $expiration ) {
                $autoload = 'no';
                add_option( $transient_timeout, time() + $expiration, '', 'no' );
            }
            $result = add_option( $transient, $value, '', $autoload );
        } else {
            if ( $expiration )
                update_option( $transient_timeout, time() + $expiration );
            $result = update_option( $transient, $value );
        }
    }
    if ( $result ) {
        do_action( 'set_transient_' . $transient );
        do_action( 'setted_transient', $transient );
    }
    return $result;
}

হুমমম $_wp_using_ext_object_cache? যদি এটি সত্য হয়, ওয়ার্ডপ্রেস স্থানান্তরগুলি সঞ্চয় করতে ডাটাবেসের পরিবর্তে অবজেক্ট ক্যাশে ব্যবহার করে । সুতরাং কিভাবে যে সত্য সেট করা যায়? ডাব্লুপি কীভাবে নিজের ক্যাশে এপিআই সেট আপ করে তা এক্সপ্লোর করার সময়।

আপনি প্রায় wp-load.phpবা সমস্ত কিছুর সন্ধান করতে পারেন wp-settings.php- যা উভয়ই ওয়ার্ডপ্রেসের বুটস্ট্র্যাপ প্রক্রিয়ার জন্য অত্যন্ত গুরুত্বপূর্ণ। আমাদের ক্যাশে, কিছু প্রাসঙ্গিক লাইন আছে wp-settings.php

// Start the WordPress object cache, or an external object cache if the drop-in is present.
wp_start_object_cache();

উপরে থেকে ড্রপ জিনিস মনে রাখবেন? এর কটাক্ষপাত করা যাক wp_start_object_cacheমধ্যে wp-includes/load.php

<?php
/**
 * Starts the WordPress object cache.
 *
 * If an object-cache.php file exists in the wp-content directory,
 * it uses that drop-in as an external object cache.
 *
 * @access private
 * @since 3.0.0
 */
function wp_start_object_cache() {
    global $_wp_using_ext_object_cache, $blog_id;

    $first_init = false;
    if ( ! function_exists( 'wp_cache_init' ) ) {
        if ( file_exists( WP_CONTENT_DIR . '/object-cache.php' ) ) {
            require_once ( WP_CONTENT_DIR . '/object-cache.php' );
            $_wp_using_ext_object_cache = true;
        } else {
            require_once ( ABSPATH . WPINC . '/cache.php' );
            $_wp_using_ext_object_cache = false;
        }
        $first_init = true;
    } else if ( !$_wp_using_ext_object_cache && file_exists( WP_CONTENT_DIR . '/object-cache.php' ) ) {
        // Sometimes advanced-cache.php can load object-cache.php before it is loaded here.
        // This breaks the function_exists check above and can result in $_wp_using_ext_object_cache
        // being set incorrectly. Double check if an external cache exists.
        $_wp_using_ext_object_cache = true;
    }

    // If cache supports reset, reset instead of init if already initialized.
    // Reset signals to the cache that global IDs have changed and it may need to update keys
    // and cleanup caches.
    if ( ! $first_init && function_exists( 'wp_cache_switch_to_blog' ) )
        wp_cache_switch_to_blog( $blog_id );
    else
        wp_cache_init();

    if ( function_exists( 'wp_cache_add_global_groups' ) ) {
        wp_cache_add_global_groups( array( 'users', 'userlogins', 'usermeta', 'user_meta', 'site-transient', 'site-options', 'site-lookup', 'blog-lookup', 'blog-details', 'rss', 'global-posts', 'blog-id-cache' ) );
        wp_cache_add_non_persistent_groups( array( 'comment', 'counts', 'plugins' ) );
    }
}

ফাংশনটির প্রাসঙ্গিক রেখাগুলি (যেগুলির সাথে সম্পর্কিত $_wp_using_ext_object_cacheএটি ট্রান্সিয়েন্টগুলি কীভাবে সংরক্ষণ করা হয় তা পরিবর্তন করে)।

if ( file_exists( WP_CONTENT_DIR . '/object-cache.php' ) ) {
    require_once ( WP_CONTENT_DIR . '/object-cache.php' );
    $_wp_using_ext_object_cache = true;
} else {
    require_once ( ABSPATH . WPINC . '/cache.php' );
    $_wp_using_ext_object_cache = false;
}

যদি object-cache.phpআপনার বিষয়বস্তু ডিরেক্টরিতে বিদ্যমান থাকে তবে এটি অন্তর্ভুক্ত হয়ে যায় এবং ডাব্লুপি ধরে নেয় আপনি একটি বাহ্যিক, ধ্রুবক ক্যাশে ব্যবহার করছেন - এটি $_wp_using_ext_object_cacheসত্য হয়ে যায়।

আপনি যদি কোনও বাহ্যিক অবজেক্ট ব্যবহার করছেন তবে ক্যাশে স্থানান্তরকারীরা এটি ব্যবহার করবে। যা কখন বিকল্প বনাম ট্রান্সজেন্ট ব্যবহার করবে তা নিয়ে আসে।

সহজ। অনির্দিষ্টকালের জন্য অবিরত থাকতে যদি আপনার ডেটা প্রয়োজন হয় তবে বিকল্পগুলি ব্যবহার করুন। তারা "ক্যাশেড" পেয়ে যায় তবে তাদের প্রচলিত উত্স হ'ল ডেটাবেস এবং কোনও ব্যবহারকারী সুস্পষ্টভাবে অনুরোধ না করলে এগুলি কখনই চলে যাবে না।

ডেটাগুলির জন্য যা নির্দিষ্ট সময়ের জন্য সঞ্চয় করা উচিত, তবে নির্দিষ্ট জীবনকাল ব্যবহারের স্থানান্তরগুলি অতিক্রম করার দরকার নেই। অভ্যন্তরীণভাবে, ডব্লিউপি কোনও বাহ্যিক, অবিচ্ছিন্ন অবজেক্ট ক্যাশে ব্যবহার করার চেষ্টা করবে যদি তা না পারলে ডেটা বিকল্প টেবিলের মধ্যে চলে যেতে পারে এবং ওয়ার্ডপ্রেস এর পিচিউড-ক্রনের মাধ্যমে মেয়াদ শেষ হয়ে গেলে সংগ্রহ করবে ।

কিছু অন্যান্য উদ্বেগ / প্রশ্ন:

  1. এক টন কল করা কি ঠিক আছে get_option? সম্ভবত। তারা একটি কার্য ওভারহেডে কলটি চাপায় তবে এটি সম্ভবত ডেটাবেসে আঘাত হানে না। আপনার পছন্দসই ভাষা কোনও পৃষ্ঠা উত্পন্ন করার চেয়ে ডেটাবেস লোড প্রায়শই ওয়েব অ্যাপ্লিকেশন স্কেলাবিলিটিতে একটি বড় উদ্বেগ।
  2. আমি কীভাবে ট্রান্সজেন্ট বনাম ক্যাশে এপিআই ব্যবহার করতে পারি? যদি আপনি কোনও নির্দিষ্ট সময়ের জন্য ডেটা ধরে রাখার প্রত্যাশা করেন তবে ক্ষণস্থায়ী এপিআই ব্যবহার করুন API যদি ডেটা অব্যাহত থাকে তবে এটি বিবেচনা করে না (যেমন, ডেটা গণনা / আনতে খুব বেশি সময় লাগে না, তবে পৃষ্ঠার লোড প্রতি এটি একবারের বেশি হওয়া উচিত নয়) ক্যাশে এপিআই ব্যবহার করুন।
  3. সমস্ত অপশন আসলেই প্রতিটি পেজ লোডে ক্যাশে থাকে? অগত্যা। যদি আপনি add_optionএটির শেষ, noalচ্ছিক যুক্তি দিয়ে কল করেন কারণ সেগুলি স্বয়ংক্রিয়ভাবে না। এটি বলেছিল, একবার আপনি একবার এনে ফেললে, তারা ক্যাশে যায় এবং পরবর্তী কলগুলি ডাটাবেসে হিট হয় না।

নাইটপিক 1: পৃষ্ঠা শুরুতে সমস্ত অপশন লোড হয় না তবে তৈরি হওয়ার সময় কেবল "অটোল্যাড = হ্যাঁ" চিহ্নিত করা হয় are অ্যাড_পশনটিতে সেই প্যারামিটারের জন্য ডিফল্ট হ্যাঁ 'হ'ল এবং বেশিরভাগ প্লাগইন লেখকরা সেখানে' না 'ব্যবহারের পার্থক্য বোঝার জন্য বিরক্ত হন না আপনার বক্তব্যটি কার্যত সত্য করে তোলে।
মার্ক কাপলুন

এমনকি অ-অটোল্যাডযুক্ত বিকল্পগুলি একবার এনে দেওয়ার পরে তা ক্যাশে করা হয়। এগুলি প্রাথমিকভাবে লোড করা নাও হতে পারে তবে তারা পরে বস্তুর ক্যাশে যাবে। এমনকি যে বিকল্পগুলি বিদ্যমান নেই সেগুলি ক্যাশে করা হয়! github.com/WordPress/WordPress/blob/master/wp-includes/… তবে অটোলোড বিকল্পটি সম্পর্কে আমি একটি নোট যুক্ত করেছি।
chrisguitarguy

সেটি ছিল নাইটপিক 2;)
মার্ক

দুর্দান্ত নিবন্ধটির জন্য এবং সময়টির জন্য সমস্ত কিছু সংক্ষিপ্তসার জন্য আপনাকে ধন্যবাদ।
prosti থেকে

5

আমি জানি 4 টি ক্যাশে ধরণের রয়েছে

  1. তুচ্ছ - এটি সর্বদা চালু থাকে এবং অন্য কোনও ক্যাচিং খেলতে আসার আগে তা প্রভাবিত করে। এটি ক্যাচড আইটেমগুলি একটি পিএইচপি অ্যারেতে সঞ্চয় করে যার অর্থ এটি আপনার পিএইচপি এক্সিকিউশন সেশন থেকে মেমরি গ্রহণ করে এবং পিএইচপি এক্সিকিউশন শেষ হওয়ার পরে ক্যাশেটি খালি করা হয়। যেমন এমনকি অন্য কোনও ক্যাশে ব্যবহার না করেও যদি আপনি পর পর দুবার get_option ('opt') কল করেন তবে আপনি প্রথমবার একটি ডিবি ক্যোয়ারী তৈরি করবেন এবং দ্বিতীয় বারের মানটি মেমরি থেকে ফিরে আসবে।

  2. ফাইল - ক্যাশেড মানগুলি আপনার মূল ডিরেক্টরিতে কোথাও ফাইলগুলিতে সংরক্ষণ করা হয়। আমি বিশ্বাস করি যে আপনি যদি খুব দ্রুত ডিস্ক বা মেমরি ম্যাপযুক্ত ফাইল স্টোরেজ না করেন তবে এটি পারফরম্যান্সের ক্ষেত্রে কার্যকর নয়।

  3. এপিসি (বা অন্যান্য পিএইচপি এক্সিলার ভিত্তিক ক্যাশে) - ক্যাশেড মানগুলি আপনার হোস্ট মেশিনের মেমরিতে এবং আপনার পিএইচপি মেমরির বরাদ্দের বাইরে সংরক্ষণ করা হয়। সর্বাধিক সম্ভাব্য সমস্যাটি হ'ল ডেটার কোনও স্কোপিং নেই এবং আপনি যদি দুটি সাইট চালনা করেন তবে প্রতিটি একে অপরের ক্যাশেড ডেটা অ্যাক্সেস করতে বা এটি ওভাররাইট করতে পারে।

  4. মেমকেচে - এটি একটি নেটওয়ার্ক ভিত্তিক ক্যাশে। আপনি নেটওয়ার্কের যে কোনও জায়গায় ক্যাচিং পরিষেবা চালাতে পারেন এবং এটি সম্ভবত এর হোস্ট মেমোরিতে মান সংরক্ষণ করে। আপনি যদি ভারতে ভারসাম্য বজায় না রাখেন তবে সম্ভবত আপনাকে মেমক্যাচের দরকার নেই।

বিটিডাব্লু, অবজেক্ট ক্যাশিং অপশনগুলির চেয়ে অনেক বেশি ক্যাশে করছে, এটি উচ্চ স্তরের ডাব্লুপিআই এপিআই ব্যবহার করে ডিবি থেকে প্রাপ্ত প্রায় সব কিছু সংরক্ষণ করবে।


আমি জানি উত্তরটি বেশ পুরানো, তবে আমি দুর্দান্ত রেডিসও যুক্ত করব
ক্র্যানিও

@ ক্র্যানিও, আপনি ঠিক বলেছেন তবে ... রেডিস মূলত স্টোরেজ সহ মেমক্যাশের একটি বৈকল্পিক এবং এর জন্য এটি একটি (নোএসকিউএল) ডিবি। এই আইএমএইচওটি আসলে খারাপ, যেমন নোড ব্যর্থ হয় বা আপডেট করা যায় না তবে আপনি এটি থেকে বাসি তথ্য পেতে পারেন। এটির মতো আচরণের মতো ডিবি বন্ধ করার বিকল্প রয়েছে তবে আমি নিশ্চিত নই যে এটি ডিফল্টরূপে চালু বা বন্ধ রয়েছে।
মার্ক কাপলুন

এটি মেমক্যাচড (আরও ভাল) এর জন্য একটি নিখুঁত প্রতিস্থাপন, আপনার আর কী দরকার? এখন পর্যন্ত আমি যে সর্বাধিক সাধারণ ব্যবহার দেখেছি তা হ'ল র‌্যামের মূল-মান স্টোরেজ হিসাবে (হ্যাঁ, এগুলি ছাড়াও, ডেটা স্থির করা যায়, ক্লাস্টারিংয়ের পথে রয়েছে, এবং ক্যু পরিচালনার ক্ষমতা রয়েছে, তবে প্রত্যেকে রেডিসকে একটি দুর্দান্ত হিসাবে যুক্ত করেছে ডাব্লুপি এর জন্য ক্যাশে করার বিকল্প)
ক্র্যানিও

প্রত্যেকেই সেতুতেও ঝাঁপিয়ে উঠতে পারে;) তবে
ক্যাচিংয়ের

এটি সম্পূর্ণ অর্থহীন; আপনি র‌্যাম ক্যাচিং চান, রেডিস র‌্যাম ক্যাচিং করেন, পিরিয়ড; এবং এটি আশ্চর্যজনকভাবে এটি করে। আপনি যদি এটির জন্য যেতে না চান তবে একেবারে কোনও যুক্ত জটিলতা নেই । সুতরাং, স্যার, আমি সত্যিই আপনার বক্তব্য বুঝতে ব্যর্থ।
ক্র্যানিও

0

বিকল্পগুলি সর্বদা ডেটাবেজে সংরক্ষণ করা হয়, তবে ট্রান্সিয়েন্টগুলি কেবল ভাগ করা মেমরিতে সংরক্ষণ করা যেতে পারে যদি এপিসি এবং ডাব্লুপি-তে এপিসি ক্যাচিং প্রয়োগকারী একটি প্লাগইন ইনস্টল করা থাকে। মেমকেচে স্মৃতিও ব্যবহার করে।

বিকল্পগুলি মেমোরিতেও সঞ্চয় করা হয় এবং যখন সম্ভব হয় সেখান থেকে লোড করা হয় (যদি না হয় তবে একটি ডিবি কোয়েরি সম্পন্ন হয়)।


0

দুর্দান্ত প্রশ্ন।

আমি মনে করি কীভাবে ওয়ার্ডপ্রেস WP_Object_Cacheক্লাস ব্যবহার করে সেই অংশটি এখনও নেই, তাই আমি এটি যুক্ত করব।

দস্তাবেজগুলি থেকে:

ডেএফ: ওয়ার্ডপ্রেস অবজেক্ট ক্যাশে ডাটাবেসের ভ্রমণের সময় সংরক্ষণ করতে ব্যবহৃত হয়। অবজেক্ট ক্যাশে সমস্ত ক্যাশে ডেটা মেমোরিতে সঞ্চয় করে এবং একটি কী ব্যবহার করে ক্যাশে সামগ্রীগুলি উপলব্ধ করে, যা নাম এবং পরে ক্যাশের সামগ্রীগুলি পুনরুদ্ধার করতে ব্যবহৃত হয়।

এই WP_Object_Cacheকাঠামো এখানে ।

এখানে চিত্র বর্ণনা লিখুন

নোট + জনসাধারণ, - ব্যক্তিগত, # সুরক্ষিত।

আপনি stats()পদ্ধতিটি বিশ্বব্যাপী ক্যাশে অবজেক্ট এবং সেখানে কী আছে তা সম্পর্কে সাধারণ পরিসংখ্যান দেখানোর জন্য ব্যবহার করেন । এখানে ফলাফল:

Cache Hits: 110
Cache Misses: 98

Group: options - ( 81.03k )
Group: default - ( 0.03k )
Group: users - ( 0.41k )
Group: userlogins - ( 0.03k )
Group: useremail - ( 0.04k )
Group: userslugs - ( 0.03k )
Group: user_meta - ( 3.92k )
Group: posts - ( 1.99k )
Group: terms - ( 1.76k )
Group: post_tag_relationships - ( 0.04k )
Group: category_relationships - ( 0.03k )
Group: post_format_relationships - ( 0.02k )
Group: post_meta - ( 0.36k )

এই যেমন আমি একটি টেমপ্লেট খুব প্রথম দিকে পেয়েছিলাম single.php

উল্লেখ্য পরিবর্তনশীল আমরা আগ্রহী হল: global $wp_object_cache

ব্যক্তিগত সদস্যটি $cacheপ্রকৃত ক্যাশিং ডেটা ধারণ করে।

প্রোগ্রামিংয়ে, ক্যাশে স্ট্রাকচারগুলি সর্বত্র রয়েছে। একটি সাধারণ ফর্ম এ তারা একটি মূল মান জোড়া হিসাবে স্বীকৃত হতে পারে। বালতি, NoDB কাঠামো, ডাটাবেস সূচী। ওয়ার্ডপ্রেস অবজেক্ট ক্যাশে চূড়ান্ত লক্ষ্যটি ছিল সহজতম কাঠামো না থাকলেও মূল মান জোড়গুলি স্বীকৃত হতে পারে।

যেহেতু আমি single.phpক্যাশে প্রিন্ট করার সময় ছিলাম:

print_r($wp_object_cache->cache['posts']);

আমি একক পোস্টে ক্যাশে পাচ্ছি।

    [last_changed] => 0.34169600 1481802075
    [get_page_by_path:2516f01e446b6c125493ec7824b63868:0.34169600 1481802075] => 0
    [2831] => WP_Post Object
        (
            [ID] => 2831
            [post_author] => 1 
            ... the cached post object goes here
        )

অবজেক্টটির মান হবে এবং ক্যাশিং কী হবে

get_page_by_path:2516f01e446b6c125493ec7824b63868:0.34169600 1481802075

এখানে আপনি $cache_keyকাঠামোটি পরীক্ষা করতে পারেন :

File: /wp-includes/post.php
4210: /**
4211:  * Retrieves a page given its path.
4212:  *
4213:  * @since 2.1.0
4214:  *
4215:  * @global wpdb $wpdb WordPress database abstraction object.
4216:  *
4217:  * @param string       $page_path Page path.
4218:  * @param string       $output    Optional. The required return type. One of OBJECT, ARRAY_A, or ARRAY_N, which correspond to
4219:  *                                a WP_Post object, an associative array, or a numeric array, respectively. Default OBJECT.
4220:  * @param string|array $post_type Optional. Post type or array of post types. Default 'page'.
4221:  * @return WP_Post|array|null WP_Post (or array) on success, or null on failure.
4222:  */
4223: function get_page_by_path( $page_path, $output = OBJECT, $post_type = 'page' ) {
4224:   global $wpdb;
4225: 
4226:   $last_changed = wp_cache_get_last_changed( 'posts' );
4227: 
4228:   $hash = md5( $page_path . serialize( $post_type ) );
4229:   $cache_key = "get_page_by_path:$hash:$last_changed";
4230:   $cached = wp_cache_get( $cache_key, 'posts' );
4231:   if ( false !== $cached ) {
4232:       // Special case: '0' is a bad `$page_path`.
4233:       if ( '0' === $cached || 0 === $cached ) {
4234:           return;
4235:       } else {
4236:           return get_post( $cached, $output );
4237:       }
4238:   }
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.