linux文件系统dentry_Linux文件系统(四)---三大缓冲区之inode缓冲区 (内存inode映像 )...

在文件系统中,有三大缓冲为了提升效率:inode缓冲区、dentry缓冲区、块缓冲。

(内核:2.4.37)

一、inode缓冲区

为了加快对索引节点的索引,引入inode缓冲区,下面我们看Linux/fs/inode.c代码。inode缓冲区代码

1、一些数据结构:

之前已经说过,有多个链表用于管理inode节点:

59 static LIST_HEAD(inode_in_use);

60 static LIST_HEAD(inode_unused);

61 static LIST_HEAD(inode_unused_pagecache);

62 static struct list_head *inode_hashtable;

63 static LIST_HEAD(anon_hash_chain); /* for inodes with NULL i_sb */inode_in_use:正在使用的inode,即有效的inode,i_count > 0且i_nlink > 0。

inode_unused:有效的节点,但是还没有使用,处于空闲状态。(数据不在pagecache中)。

inode_unused_pagecache:同上。(数据在pagecache中)。

inode_hashtable:用于inode在hash表中,提高查找效率。

anon_hash_chain:用于超级块是空的的inodes。例如:sock_alloc()函数, 通过调用fs/inode.c中get_empty_inode()创建的套接字是一个匿名索引节点,这个节点就加入到了anon_hash_chain链表。

dirty:用于保存超级块中的所有的已经修改的inodes。

76 struct inodes_stat_t inodes_stat;

77

78 static kmem_cache_t * inode_cachep;上面的两个字段:

inodes_stat:记录inodes节点的状态。

inode_cachep:对inodes对象的缓存块。

2、基本初始化:初始化inode哈希表头和slab内存缓存块

索引节点高速缓存的初始化是由inode_init()实现的,现在看看下面代码:

1296 /*

1297 * Initialize the hash tables.

1298 */

1299 void __init inode_init(unsigned long mempages) /* 参数:表示inode缓存使用的物理页面数 */

1300 {

1301 struct list_head *head;

1302 unsigned long order;

1303 unsigned int nr_hash;

1304 int i;

1305 /* 下面的一段操作就是根据PAGE_SHIFT,PAGE_SIZE给hash表分配空间 */

1306 mempages >>= (14 - PAGE_SHIFT);

1307 mempages *= sizeof(struct list_head);

1308 for (order = 0; ((1UL << order) << PAGE_SHIFT) < mempages; order++)

1309 ;

1310

1311 do {

1312 unsigned long tmp;

1313

1314 nr_hash = (1UL << order) * PAGE_SIZE /

1315 sizeof(struct list_head);

1316 i_hash_mask = (nr_hash - 1);

1317

1318 tmp = nr_hash;

1319 i_hash_shift = 0;

1320 while ((tmp >>= 1UL) != 0UL)

1321 i_hash_shift++;

1322 /* inode_hashtable是一个全局变量,用于hash表,上面说过,需要预定order页的内存作为inode-hash表使用 */

1323 inode_hashtable = (struct list_head *)

1324 __get_free_pages(GFP_ATOMIC, order);

1325 } while (inode_hashtable == NULL && --order >= 0);

1326

1327 printk(KERN_INFO "Inode cache hash table entries: %d (order: %ld, %ld bytes)\n",

1328 nr_hash, order, (PAGE_SIZE << order));

1329 /* 如果分配不成功就失败 */

1330 if (!inode_hashtable)

1331 panic("Failed to allocate inode hash table\n");

1332 /* 下面就是初始化每个inde-hash节点 */

1333 head = inode_hashtable;

1334 i = nr_hash;

1335 do {

1336 INIT_LIST_HEAD(head);

1337 head++;

1338 i--;

1339 } while (i);

1340

1341 /* inode slab cache:创建一个inode的slab缓存,以后的inode缓存都从这个slab中进行分配 */

1342 inode_cachep = kmem_cache_create("inode_cache", sizeof(struct inode),

1343 0, SLAB_HWCACHE_ALIGN, init_once,

1344 NULL);

1345 if (!inode_cachep)

1346 panic("cannot create inode slab cache");

1347

1348 unused_inodes_flush_task.routine = try_to_sync_unused_inodes;

1349 }

1350

注意上面的逻辑,说明两个问题:

1).  第一初始化inode_hashtable作为链表的头。

2).  初始化inode的slab缓存,也就是说,如果我需要分配一个inode缓存在内存中,那么都从这个inode_cachep中分配一个inode内存节点。然后统一加入到这个inode_hashtable中进行管理!也就是所谓的创建inode slab分配器缓存。

下面看看具体的缓存的分配过程:

先看init_once函数:

169 static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)

170 {

171 struct inode * inode = (struct inode *) foo;

172

173 if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==

174 SLAB_CTOR_CONSTRUCTOR)

175 inode_init_once(inode);

176 }

注意:在上面的kmem_cache_create函数中,执行的顺序是:

---> kmem_cache_create(里面重要的一步是cachep->ctor = ctor; cachep->dtor = dtor;)

---> kmem_cache_alloc

---> __kmem_cache_alloc

---> kmem_cache_grow(里面一个重要设置是:ctor_flags = SLAB_CTOR_CONSTRUCTOR;)

---> kmem_cache_init_objs:里面会执行cachep->ctor(objp, cachep, ctor_flags);

这样最终就跳转到上面的init_once函数中了!在init函数中执行的是inode_init_once函数:

141 /*

142 * These are initializations that only need to be done

143 * once, because the fields are idempotent across use

144 * of the inode, so let the slab aware of that.

145 */

146 void inode_init_once(struct inode *inode)

147 {

148 memset(inode, 0, sizeof(*inode));

149 __inode_init_once(inode);

150 }

再看__inode_init_once函数:

152 void __inode_init_once(struct inode *inode)

153 {

154 init_waitqueue_head(&inode->i_wait);

155 INIT_LIST_HEAD(&inode->i_hash);

156 INIT_LIST_HEAD(&inode->i_data.clean_pages);

157 INIT_LIST_HEAD(&inode->i_data.dirty_pages);

158 INIT_LIST_HEAD(&inode->i_data.locked_pages);

159 INIT_LIST_HEAD(&inode->i_dentry);

160 INIT_LIST_HEAD(&inode->i_dirty_buffers);

161 INIT_LIST_HEAD(&inode->i_dirty_data_buffers);

162 INIT_LIST_HEAD(&inode->i_devices);

163 sema_init(&inode->i_sem, 1);

164 sema_init(&inode->i_zombie, 1);

165 init_rwsem(&inode->i_alloc_sem);

166 spin_lock_init(&inode->i_data.i_shared_lock);

167 }

3、注意知道现在我们主要说了上面的两个基本的问题(红字部分),但是这只是一个框架而已,对于具体的一个文件系统来说怎么个流程,下面需要看看!

我们以最常见的ext2作为说明:

现在一个ext2类型的文件系统想要创建一个inode,那么执行:ext2_new_inode函数

314 struct inode * ext2_new_inode (const struct inode * dir, int mode)

315 {

316 struct super_block * sb;

317 struct buffer_head * bh;

318 struct buffer_head * bh2;

319 int group, i;

320 ino_t ino;

321 struct inode * inode;

322 struct ext2_group_desc * desc;

323 struct ext2_super_block * es;

324 int err;

325

326 sb = dir->i_sb;

327 inode = new_inode(sb); /* 创建一个inode节点,这个函数就是在fs/inode.c中的new_inode函数 */

328 if (!inode)

329 return ERR_PTR(-ENOMEM);

330

331 lock_super (sb);

332 es = sb->u.ext2_sb.s_es;

333 repeat:

334 if (S_ISDIR(mode))

335 group = find_group_dir(sb, dir->u.ext2_i.i_block_group);

336 else

337 group = find_group_other(sb, dir->u.ext2_i.i_block_group);

338

339 err = -ENOSPC;

340 if (group == -1)

341 goto fail;

342

343 err = -EIO;

344 bh = load_inode_bitmap (sb, group);

345 if (IS_ERR(bh))

346 goto fail2;

347

348 i = ext2_find_first_zero_bit ((unsigned long *) bh->b_data,

349 EXT2_INODES_PER_GROUP(sb));

350 if (i >= EXT2_INODES_PER_GROUP(sb))

351 goto bad_count;

352 ext2_set_bit (i, bh->b_data);

353

354 mark_buffer_dirty(bh);

355 if (sb->s_flags & MS_SYNCHRONOUS) {

356 ll_rw_block (WRITE, 1, &bh);

357 wait_on_buffer (bh);

358 }

359

360 ino = group * EXT2_INODES_PER_GROUP(sb) + i + 1;

361 if (ino < EXT2_FIRST_INO(sb) || ino > le32_to_cpu(es->s_inodes_count)) {

362 ext2_error (sb, "ext2_new_inode",

363 "reserved inode or inode > inodes count - "

364 "block_group = %d,inode=%ld", group, ino);

365 err = -EIO;

366 goto fail2;

367 }

368

369 es->s_free_inodes_count =

370 cpu_to_le32(le32_to_cpu(es->s_free_inodes_count) - 1);

371 mark_buffer_dirty(sb->u.ext2_sb.s_sbh);

372 sb->s_dirt = 1;

373 inode->i_uid = current->fsuid;

374 if (test_opt (sb, GRPID))

375 inode->i_gid = dir->i_gid;

376 else if (dir->i_mode & S_ISGID) {

377 inode->i_gid = dir->i_gid;

378 if (S_ISDIR(mode))

379 mode |= S_ISGID;

380 } else

381 inode->i_gid = current->fsgid;

382 inode->i_mode = mode;

383

384 inode->i_ino = ino;

385 inode->i_blksize = PAGE_SIZE; /* This is the optimal IO size (for stat), not the fs block size */

386 inode->i_blocks = 0;

387 inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;

388 inode->u.ext2_i.i_state = EXT2_STATE_NEW;

389 inode->u.ext2_i.i_flags = dir->u.ext2_i.i_flags & ~EXT2_BTREE_FL;

390 if (S_ISLNK(mode))

391 inode->u.ext2_i.i_flags &= ~(EXT2_IMMUTABLE_FL|EXT2_APPEND_FL);

392 inode->u.ext2_i.i_block_group = group;

393 ext2_set_inode_flags(inode);

394 insert_inode_hash(inode); /* 将这个新的inode内存节点挂在hashtable中,这个函数在fs/inode.c中的insert_inode_hash函数 */

395 inode->i_generation = event++;

396 mark_inode_dirty(inode);

397

398 unlock_super (sb);

399 if(DQUOT_ALLOC_INODE(inode)) {

400 DQUOT_DROP(inode);

401 inode->i_flags |= S_NOQUOTA;

402 inode->i_nlink = 0;

403 iput(inode);

404 return ERR_PTR(-EDQUOT);

405 }

406 ext2_debug ("allocating inode %lu\n", inode->i_ino);

407 return inode;

408

409 fail2:

410 desc = ext2_get_group_desc (sb, group, &bh2);

411 desc->bg_free_inodes_count =

412 cpu_to_le16(le16_to_cpu(desc->bg_free_inodes_count) + 1);

413 if (S_ISDIR(mode))

414 desc->bg_used_dirs_count =

415 cpu_to_le16(le16_to_cpu(desc->bg_used_dirs_count) - 1);

416 mark_buffer_dirty(bh2);

417 fail:

418 unlock_super(sb);

419 make_bad_inode(inode);

420 iput(inode);

421 return ERR_PTR(err);

422

423 bad_count:

424 ext2_error (sb, "ext2_new_inode",

425 "Free inodes count corrupted in group %d",

426 group);

427 /* Is it really ENOSPC? */

428 err = -ENOSPC;

429 if (sb->s_flags & MS_RDONLY)

430 goto fail;

431

432 desc = ext2_get_group_desc (sb, group, &bh2);

433 desc->bg_free_inodes_count = 0;

434 mark_buffer_dirty(bh2);

435 goto repeat;

436 }这个函数比较复杂,但是我们主要看327行和394行,就是创建一个inode内存节点,然后将这个inode插入inode_hashtable中!

这个函数具体的解释不再看了,现在主要从这两个函数入手:

1). fs/inode.c中的new_inode函数,创建一个inode内存节点:

964 struct inode * new_inode(struct super_block *sb)

965 {

966 static unsigned long last_ino;

967 struct inode * inode;

968

969 spin_lock_prefetch(&inode_lock);

970

971 inode = alloc_inode(sb);/* 这个是主要的分配函数 */

972 if (inode) {

973 spin_lock(&inode_lock);

974 inodes_stat.nr_inodes++; /* inode_stat是一个所有节点状态字段,这里表明增加了一个新的inode */

975 list_add(&inode->i_list, &inode_in_use); /* 将这个inode加入到正在使用的链表中:inode_use链表 */

976 inode->i_ino = ++last_ino; /* 给这个inode分配一个inode号! */

977 inode->i_state = 0;

978 spin_unlock(&inode_lock);

979 }

980 return inode;

981 }

看看这个alloc_inode函数:

80 static struct inode *alloc_inode(struct super_block *sb)

81 {

82 static struct address_space_operations empty_aops;

83 static struct inode_operations empty_iops;

84 static struct file_operations empty_fops;

85 struct inode *inode;

86

87 if (sb->s_op->alloc_inode) /* 如果提供了自己的分配函数,那么这个文件系统自己分配去~~~,具体不多说 */

88 inode = sb->s_op->alloc_inode(sb);

89 else {

90 inode = (struct inode *) kmem_cache_alloc(inode_cachep, SLAB_KERNEL);/* 这个就是通用的分配函数,从我们初始化好的inode_cache中分配 */

91 /* will die */

92 if (inode)

93 memset(&inode->u, 0, sizeof(inode->u));

94 }

95 /* 下面初始化的东西就不多说了 */

96 if (inode) {

97 struct address_space * const mapping = &inode->i_data;

98

99 inode->i_sb = sb;

100 inode->i_dev = sb->s_dev;

101 inode->i_blkbits = sb->s_blocksize_bits;

102 inode->i_flags = 0;

103 atomic_set(&inode->i_count, 1);

104 inode->i_sock = 0;

105 inode->i_op = &empty_iops;

106 inode->i_fop = &empty_fops;

107 inode->i_nlink = 1;

108 atomic_set(&inode->i_writecount, 0);

109 inode->i_size = 0;

110 inode->i_blocks = 0;

111 inode->i_bytes = 0;

112 inode->i_generation = 0;

113 memset(&inode->i_dquot, 0, sizeof(inode->i_dquot));

114 inode->i_pipe = NULL;

115 inode->i_bdev = NULL;

116 inode->i_cdev = NULL;

117

118 mapping->a_ops = &empty_aops;

119 mapping->host = inode;

120 mapping->gfp_mask = GFP_HIGHUSER;

121 inode->i_mapping = mapping;

122 }

123 return inode;

124 }

我们主要看87行和90行!看了注释也就明白了!第一种是文件系统也就是这个超级快提供了分配函数,那么就这个文件系统按照自己的意愿去分配,如果没有,那么就是要用这个通用的分配函数inode = (struct inode *) kmem_cache_alloc(inode_cachep, SLAB_KERNEL);这个函数其实很简单,其实就是在我们已经初始化好的这个inode_cache中分配一个inode内存块出来。

2). fs/inode.c中的insert_inode_hash函数,将新的分配的inode插入到inode_hashtable中:

1166 void insert_inode_hash(struct inode *inode)

1167 {

1168 struct list_head *head = &anon_hash_chain; /* anon_hash_chain是代表没有超级块的inode链表(有些临时的inode无需超级块) */

1169 if (inode->i_sb)

1170 head = inode_hashtable + hash(inode->i_sb, inode->i_ino); /* 这个是正常的插入 */

1171 spin_lock(&inode_lock);

1172 list_add(&inode->i_hash, head);

1173 spin_unlock(&inode_lock);

1174 }

注意这个hash表其实就可以看做是一个数组链表组合体,如图所示:

99ea7c67df543fc6020101265ccf5825.png

head = inode_hashtable + hash(inode->i_sb, inode->i_ino);这一行就是通过这个hash函数算出hash值,找到这个inode应该放在哪一列。譬如定位到第三列,那么第三列中的都是hash值相同的inode。然后所有的这列inode都是构成双向链表的。注意inode中的i_hash字段就做这个事的!!list_add(&inode->i_hash, head);函数就是将hash值相同的inode构成双向链表。

看一下这个具体的hash函数(inode.c中):

1043 static inline unsigned long hash(struct super_block *sb, unsigned long i_ino)

1044 {

1045 unsigned long tmp = i_ino + ((unsigned long) sb / L1_CACHE_BYTES);

1046 tmp = tmp + (tmp >> I_HASHBITS);

1047 return tmp & I_HASHMASK;

1048 }OK,上面的具体的inode创建和加入的流程基本清楚了。具体创建的过程是涉及到内存这一块的,不多说了。

4. 下面看看给一个怎么去找到一个inode,涉及ilookup函数:

1102 struct inode *ilookup(struct super_block *sb, unsigned long ino)

1103 {

1104 struct list_head * head = inode_hashtable + hash(sb,ino);/* 获得hash值 */

1105 struct inode * inode;

1106

1107 spin_lock(&inode_lock);

1108 inode = find_inode(sb, ino, head, NULL, NULL); /* 寻找inode */

1109 if (inode) {

1110 __iget(inode);

1111 spin_unlock(&inode_lock);

1112 wait_on_inode(inode);

1113 return inode;

1114 }

1115 spin_unlock(&inode_lock);

1116

1117 return inode;

1118 }

这个函数其实比较简单了,首先还是获得这个inode的hash值定位,然后开始finde_inode:

929 static struct inode * find_inode(struct super_block * sb, unsigned long ino, struct list_head *head, find_inode_t find_actor, void *opaque)

930 {

931 struct list_head *tmp;

932 struct inode * inode;

933

934 repeat:

935 tmp = head;

936 for (;;) {

937 tmp = tmp->next;

938 inode = NULL;

939 if (tmp == head) /*双向循环链表结束条件*/

940 break;

941 inode = list_entry(tmp, struct inode, i_hash); /*获得链表中一个inode*/

942 if (inode->i_ino != ino) /*是否找到*/

943 continue;

944 if (inode->i_sb != sb) /*是否合理:是不是我需要的super_block中的inode*/

945 continue;

946 if (find_actor && !find_actor(inode, ino, opaque)) /*这个是一个查找函数指针,用户定义的一些规则是否满足*/

947 continue;

948 if (inode->i_state & (I_FREEING|I_CLEAR)) { /*注意inode节点的状态如果是free或者clear,那么等free之后再重新找*/

949 __wait_on_freeing_inode(inode);

950 goto repeat;

951 }

952 break;

953 }

954 return inode; /*返回找到的inode节点*/

955 }

上面函数最核心的本质不就是双向链表的查找么,OK。

最后:关于inode怎么工作的,将会在后面的分析ext2代码中在详细研究。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/346107.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用这些先进的GC技术提高应用程序性能

应用程序性能是我们的首要考虑因素&#xff0c;垃圾收集优化是取得小而有意义的进步的好地方 自动化垃圾收集&#xff08;与JIT HotSpot编译器一起&#xff09;是JVM中最先进&#xff0c;最有价值的组件之一&#xff0c;但是许多开发人员和工程师对垃圾收集&#xff08;GC&a…

mysql中lead_SqlServer2012中LEAD函数简单分析_MySQL

LEAD函数简单点说&#xff0c;就是把下一行的某列数据提取到当前行来显示&#xff0c;看示例更能解释清楚&#xff0c;先看测试用脚本DECLARE TestData TABLE(ID INT IDENTITY(1,1),Department VARCHAR(20),LastName VARCHAR(20),Rate FLOAT)INSERT INTO TestData(Department,L…

堆栈溢出回答了我们不知道的Java首要问题

您不应该错过的堆栈溢出问题集合&#xff1a; 这不是秘密&#xff1b; 我们都使用堆栈溢出。 它掌握了生命&#xff0c;宇宙以及几乎所有与代码相关的内容的答案。 该平台为开发人员&#xff0c;工程师和其他人员提供了一个找到他们所面临问题的答案的地方&#xff0c;或者至少…

sequelize连接mysql_node.js通过Sequelize 连接MySQL

node.js通过Sequelize 连接MySQL一.通过koa2脚手架构建项目1.1 安装koa-generator在终端输入&#xff1a;$ npm install -g koa-generator11.2 使用koa-generator生成koa2项目$ koa2 HelloKoa21成功创建项目后&#xff0c;进入项目目录&#xff0c;并执行npm install命令$ cd H…

杀java_java怎么杀掉java进程

展开全部java中有调用外部程序的e69da5e887aa62616964757a686964616f31333337623431类&#xff0c;Runtime.getRuntime().exec("./**.exe");此函数返回的是一个Process 对象&#xff0c;该对象在创建后&#xff0c;可以对它进行 destroy () 杀掉子进程、 waitFor () …

高级java开发_我最喜欢的Java高级开发人员书籍

高级java开发我上一篇博客文章 &#xff08;我对高级Java开发人员的十个最喜欢的在线资源&#xff09;的想法&#xff0c;是由Xiaoran Wang发表的“面向高级Java开发人员的十大网站”的启发。 Wang还写了一篇名为“面向Java高级开发人员的十大书籍”的文章。 就像关于高级Java开…

camera.swf java_java调用摄像头保存图片上传功能

在项目中要用到jsp页面实现网页采集摄像头图像&#xff0c;并实现上传的功能&#xff0c;页面主要js调用的&#xff0c;所以可以使用多种语言php,asp等都可以使用&#xff0c;而且是跨浏览器的。可以整合的到SSH项目中和struts1或者struts2项目中使用方法1&#xff1a;下载 pri…

java 北理工 教材_北理工《Java技术与应用》在线作业

北理工《Java技术与应用》在线作业可以代做所有奥鹏平台的作业、小论文、毕业论文、离线作业、考核作业、在线作业、在线测试&#xff0c;有需要的请联系本人一、单选题(共 20 道试题&#xff0c;共 40 分。)V1. Socket对象中____函数获取远程端口。A. getPort( )B. getLocalPo…

Apache Spark Job的剖析

Apache Spark是通用的大规模数据处理框架。 了解spark如何执行作业对于获取大部分作业非常重要。 关于Spark评估范式的简短回顾&#xff1a;Spark使用的是惰性评估范式&#xff0c;在该范式中&#xff0c;Spark应用程序在驱动程序调用“ Action”之前不会执行任何操作。 惰性…

scala本地调试_如何编写自己的Java / Scala调试器

scala本地调试在本文中&#xff0c;我们将探讨Java / Scala调试器的编写和工作方式。 诸如Windows的WinDbg或Linux / Unix的gdb之类的本机调试器通过操作系统直接提供给它们的钩子来获取其功能&#xff0c;以监视和操纵外部进程的状态。 JVM充当OS之上的抽象层&#xff0c;它提…

java content()_Java contentEquals() 方法

全屏Java contentEquals() 方法contentEquals() 方法用于将将此字符串与指定的 StringBuffer 比较。语法public boolean contentEquals(StringBuffer sb)参数sb -- 要与字符串比较的 StringBuffer。返回值如字符串与指定 StringBuffer 表示相同的字符序列&#xff0c;则返回 tr…

通过这5个简单的技巧减少GC开销

编写代码的五种简单方法&#xff0c;可提高内存效率&#xff0c;而无需花费更多时间或降低代码可读性 垃圾回收会为您的应用程序增加多少开销&#xff1f; 您可能不知道确切的数字&#xff0c;但您确实知道总有改进的余地。 尽管自动GC是最有效的过程&#xff0c;但是如果它过…

内部简单二进制编码(SBE)

SBE是用于金融行业的非常快速的序列化库&#xff0c;在本博客中&#xff0c;我将介绍一些使其快速发展的设计选择。 序列化的全部目的是对消息进行编码和解码&#xff0c;并且有很多可用的选项&#xff0c;从XML&#xff0c;JSON&#xff0c;Protobufer&#xff0c;Thrift&…

mingw64 下 java_在 Windows 10 64 位下安装 Mingw-w64

1、MinGW 的全称是&#xff1a;Minimalist GNU on Windows 。打开网址&#xff1a;http://www.mingw-w64.org/doku.php/download &#xff0c;选择 MingW-W64-builds。如图1图12、下载包名&#xff1a;mingw-w64-install.exe。安装时报错&#xff1a;Cannot download repositor…

java实现layui分页_layui如何实现数据分页功能

我们先来看下官网的演示画面。具体代码&#xff1a;页面引入layui.css、 layui.js前台jsvar limitcount 10;var curnum 1;//列表查询方法function productsearch(productGroupId,start,limitsize) {layui.use([table,laypage,laydate], function(){var table layui.table,la…

java 合并到一行_mysql中将多行数据合并成一行数据

一个字段可能对应多条数据&#xff0c;用mysql实现将多行数据合并成一行数据例如&#xff1a;一个活动id(activeId)对应多个模块名(modelName),按照一般的sql语句&#xff1a;1 SELECT am.activeId,m.modelName2 FROM activemodel am3 JOIN model m4 ON am.modelId m.modelId5…

容器化Spring Data Cassandra应用程序

我正在继续学习Docker的旅程。 在这一点上&#xff0c;我仍然保持简单。 这次&#xff0c;我将解决将Spring和Cassandra应用程序转换为使用容器而不是在主机上本地运行的问题。 更准确地说&#xff0c;使用Spring Data Cassandra整理应用程序。 我希望我前几天看过进行此更改。…

使用React和Spring Boot构建一个简单的CRUD应用

“我喜欢编写身份验证和授权代码。” 〜从来没有Java开发人员。 厌倦了一次又一次地建立相同的登录屏幕&#xff1f; 尝试使用Okta API进行托管身份验证&#xff0c;授权和多因素身份验证。 React的设计使创建交互式UI变得轻松自如。 它的状态管理非常有效&#xff0c;并且仅在…

使用CUBA进行开发–是Spring的重大转变吗?

阅读另一个供内部公司使用的Web项目的要求时&#xff0c;您&#xff08;至少是我自己&#xff09;通常会看到一个很普通的集合&#xff1a;定义明确的数据存储结构&#xff08;或有时是现有的旧式DB&#xff09;&#xff0c;大量的数据输入形式&#xff0c;非常复杂的业务逻辑&…

java 伴随矩阵_C#计算矩阵的逆矩阵方法实例分析

本文实例讲述了C#计算矩阵的逆矩阵方法。分享给大家供大家参考。具体如下&#xff1a;1.代码思路1)对矩阵进行合法性检查&#xff1a;矩阵必须为方阵2)计算矩阵行列式的值(Determinant函数)3)只有满秩矩阵才有逆矩阵&#xff0c;因此如果行列式的值为0(在代码中以绝对值小于1E-…