Nøgleværdibutik med kronikerkort

1. Oversigt

I denne vejledning skal vi se, hvordan vi kan bruge Chronicle Map til lagring af nøgleværdipar. Vi opretter også korte eksempler for at demonstrere dets opførsel og anvendelse.

2. Hvad er et krønikakort?

Efter dokumentationen “Chronicle Map er en superhurtig, ikke-blokerende nøgleværdilager i hukommelse, designet til applikationer med lav latenstid og / eller multi-proces”.

Kort sagt er det en nøgleværdibutik uden for bunken. Kortet kræver ikke en stor mængde RAM for at det skal fungere korrekt. Det kan vokse baseret på den tilgængelige diskkapacitet. Desuden understøtter den replikering af dataene i en multi-master serveropsætning.

Lad os nu se, hvordan vi kan konfigurere og arbejde med det.

3. Maven-afhængighed

For at komme i gang skal vi tilføje afhængighed af kronikerkort til vores projekt:

 net.openhft kronik-kort 3.17.2 

4. Typer af krønikekort

Vi kan oprette et kort på to måder: enten som et hukommelseskort eller som et vedvarende kort.

Lad os se begge disse detaljeret.

4.1. Kort i hukommelsen

Et in-memory Chronicle Map er et kortlager, der oprettes i serverens fysiske hukommelse. Det betyder det er kun tilgængeligt inden for JVM-processen, hvor kortbutikken oprettes.

Lad os se et hurtigt eksempel:

ChronicleMap inMemoryCountryMap = ChronicleMap .of (LongValue.class, CharSequence.class) .name ("country-map") .poster (50) .averageValue ("America") .create ();

For enkelheds skyld opretter vi et kort, der gemmer 50 land-id'er og deres navne. Som vi kan se i kodestykket, er oprettelsen ret ligetil bortset fra gennemsnits værdi() konfiguration. Dette fortæller kortet at konfigurere det gennemsnitlige antal bytes taget af kortindtastningsværdier.

Med andre ord, Når du opretter kortet, bestemmer Chronicle Map det gennemsnitlige antal bytes taget af den serielle form for værdier. Det gør det ved at serialisere den givne gennemsnitsværdi ved hjælp af de konfigurerede værdibevægere. Derefter tildeles det bestemte antal bytes til værdien af ​​hver kortindgang.

En ting, vi skal bemærke, når det kommer til hukommelseskortet, er, at dataene kun er tilgængelige, når JVM-processen er i live. Biblioteket rydder dataene, når processen afsluttes.

4.2. Vedvarende kort

I modsætning til et hukommelseskort, implementeringen gemmer et vedvarende kort på disken. Lad os nu se, hvordan vi kan oprette et vedvarende kort:

ChronicleMap persistedCountryMap = ChronicleMap .of (LongValue.class, CharSequence.class) .name ("country-map"). Entries (50) .averageValue ("America") .createPersistedTo (new File (System.getProperty ("user.home) ") +" /country-details.dat "));

Dette opretter en fil, der kaldes land-detaljer. dat i den angivne mappe. Hvis denne fil allerede er tilgængelig i den angivne sti, åbner bygherreimplementeringen et link til det eksisterende datalager fra denne JVM-proces.

Vi kan gøre brug af det vedvarende kort i tilfælde, hvor vi vil have det:

  • overleve ud over skaberen processen; for eksempel til at understøtte hot-applikationsomlægning
  • gør det globalt på en server; for eksempel at understøtte flere samtidige procesadgang
  • fungere som et datalager, som vi gemmer på disken

5. Konfiguration af størrelse

Det er obligatorisk at konfigurere gennemsnitsværdien og gennemsnitsnøglen, mens du opretter et krønikakort, undtagen i det tilfælde, hvor vores nøgle / værditype enten er en primitiv eller en værdiinterface i boks. I vores eksempel konfigurerer vi ikke den gennemsnitlige nøgle siden nøgletypen LongValue er en værdigrænseflade.

Lad os nu se, hvad mulighederne er for at konfigurere det gennemsnitlige antal nøgle- / værdibytes:

  • gennemsnits værdi() - Den værdi, hvorfra det gennemsnitlige antal bytes, der skal tildeles for værdien af ​​en kortindgang, bestemmes
  • averageValueSize () - Det gennemsnitlige antal bytes, der skal tildeles for værdien af ​​en kortindgang
  • constantValueSizeBySample () - Antallet af bytes, der skal tildeles til værdien af ​​en kortindgang, når værdien altid er den samme
  • gennemsnitsnøgle () - Nøglen, hvorfra det gennemsnitlige antal bytes, der skal tildeles for nøglen til en kortindgang, bestemmes
  • averageKeySize () - Det gennemsnitlige antal bytes, der skal tildeles for nøglen til en kortindgang
  • constantKeySizeBySample () - Antallet af bytes, der skal tildeles til nøglen til en kortindgang, når størrelsen på nøglen altid er den samme

6. Nøgle- og værdityper

Der er visse standarder, som vi skal følge, når vi opretter et krønikekort, især når vi definerer nøgle og værdi. Kortet fungerer bedst, når vi opretter nøglen og værdien ved hjælp af de anbefalede typer.

Her er nogle af de anbefalede typer:

  • Værdi grænseflader
  • Enhver klasse, der implementerer Byteable interface fra Chronicle Bytes
  • Enhver klasse, der implementerer BytesMarshallable interface fra Chronicle Bytes; implementeringsklassen skal have en offentlig konstruktør uden argumenter
  • byte [] og ByteBuffer
  • CharSequence, Snorog StringBuilder
  • Heltal, Langog Dobbelt
  • Enhver klasse, der implementerer java.io. kan udvides; implementeringsklassen skal have en offentlig konstruktør uden argumenter
  • Enhver type implementering java.io.Serialiserbar, inklusive primitive typer i boks (undtagen dem, der er anført ovenfor) og arraytyper
  • Enhver anden type, hvis der leveres brugerdefinerede serialiseringer

7. Forespørgsel på et krønikakort

Chronicle Map understøtter single-key forespørgsler såvel som multi-key forespørgsler.

7.1. Enkeltnøgleforespørgsler

Enkeltnøgleforespørgsler er de operationer, der beskæftiger sig med en enkelt nøgle. ChronicleMap understøtter alle operationer fra Java Kort interface og ConcurrentMap grænseflade:

LongValue qatarKey = Værdier.newHeapInstance (LongValue.class); qatarKey.setValue (1); inMemoryCountryMap.put (qatarKey, "Qatar"); // ... CharSequence land = inMemoryCountryMap.get (nøgle);

Ud over den normale get and put-operationer, ChronicleMap tilføjer en særlig operation, getUsing (), der reducerer hukommelsesaftrykket, mens du henter og behandler en post. Lad os se dette i aktion:

LongValue-nøgle = Values.newHeapInstance (LongValue.class); StringBuilder land = nyt StringBuilder (); key.setValue (1); persistedCountryMap.getUsing (nøgle, land); assertThat (country.toString (), er (equalTo ("Rumænien"))); key.setValue (2); persistedCountryMap.getUsing (nøgle, land); assertThat (country.toString (), er (equalTo ("Indien")));

Her har vi brugt det samme StringBuilder objekt til at hente værdier for forskellige nøgler ved at sende det til getUsing () metode. Grundlæggende genbruger det samme objekt til at hente forskellige poster. I vores tilfælde er getUsing () metoden svarer til:

country.setLength (0); country.append (persistedCountryMap.get (nøgle));

7.2. Multi-Key forespørgsler

Der kan være brugstilfælde, hvor vi skal håndtere flere nøgler på samme tid. Til dette kan vi bruge queryContext () funktionalitet. Det queryContext () metode skaber en kontekst til arbejde med en kortindgang.

Lad os først oprette et multimap og tilføje nogle værdier til det:

Indstil averageValue = IntStream.of (1, 2) .boxed (). Collect (Collectors.toSet ()); ChronicleMap multiMap = ChronicleMap .of (Integer.class, (Class) (Class) Set.class) .name ("multi-map"). Entries (50) .averageValue (averageValue) .create (); Sæt set1 = nyt HashSet (); sæt1.add (1); sæt1.add (2); multiMap.put (1, sæt1); Indstil set2 = nyt HashSet (); sæt2.add (3); multiMap.put (2, set2);

For at arbejde med flere poster skal vi låse disse poster for at forhindre inkonsistens, der kan opstå på grund af en samtidig opdatering:

prøv (ExternalMapQueryContext var13 -> fistContext = multiMap.queryContext (1)) {prøv (ExternalMapQueryContext var13 -> secondContext = multiMap.queryContext (2)) {fistContext.updateLock (). lås (); secondContext.updateLock (). lås (); MapEntry firstEntry = fistContext.entry (); Indstil firstSet = firstEntry.value (). Get (); firstSet.remove (2); MapEntry secondEntry = secondContext.entry (); Indstil secondSet = secondEntry.value (). Get (); secondSet.add (4); firstEntry.doReplaceValue (fistContext.wrapValueAsData (firstSet)); secondEntry.doReplaceValue (secondContext.wrapValueAsData (secondSet)); }} endelig {assertThat (multiMap.get (1) .størrelse (), er (equalTo (1))); assertThat (multiMap.get (2) .størrelse (), er (equalTo (2))); }

8. Lukning af kronikerkortet

Nu hvor vi er færdige med at arbejde med vores kort, lad os kalde tæt() metode på vores kortobjekter for at frigøre hukommelsen uden for bunken og de ressourcer, der er knyttet til den:

persistedCountryMap.close (); inMemoryCountryMap.close (); multiMap.close ();

En ting at huske på her er, at alle korthandlinger skal være afsluttet, før kortet lukkes. Ellers kan JVM gå ned uventet.

9. Konklusion

I denne vejledning har vi lært, hvordan man bruger et Chronicle Map til at gemme og hente nøgleværdipar. Selvom community-versionen er tilgængelig med de fleste af kernefunktionaliteterne, har den kommercielle version nogle avancerede funktioner som datareplikering på tværs af flere servere og fjernopkald.

Alle eksemplerne, vi har diskuteret her, kan findes i Github-projektet.